From 158b589c2a5c9d2deb537e827ca31f93335957ea Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 22 Feb 2024 08:17:13 -0500 Subject: turned off zoom scaling for text boxes until it can be done more cleanly. fixed search to switch tabs when doc is inactive tab. --- src/client/views/nodes/formattedText/FormattedTextBox.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/client/views/nodes/formattedText/FormattedTextBox.tsx') diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index f2c4c6c8f..56008de8e 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -2019,7 +2019,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent !this._props.isContentActive() && FormattedTextBoxComment.textBox === this && FormattedTextBoxComment.Hide); const paddingX = NumCast(this.layoutDoc._xMargin, this._props.xPadding || 0); -- cgit v1.2.3-70-g09d2 From 2e99ef0512b8f1b5c089637643ff6addf5afd943 Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 4 Mar 2024 16:07:52 -0500 Subject: cleaned up a number of things related to autoHeight and stacking/masonry/notetaking views --- src/Utils.ts | 7 ++ src/client/views/ContextMenu.tsx | 5 +- src/client/views/DocumentDecorations.tsx | 10 +- src/client/views/PropertiesButtons.tsx | 3 +- .../views/collections/CollectionDockingView.tsx | 6 +- .../collections/CollectionMasonryViewFieldRow.tsx | 15 ++- .../collections/CollectionNoteTakingView.scss | 1 + .../views/collections/CollectionNoteTakingView.tsx | 107 +++++++++------------ .../collections/CollectionNoteTakingViewColumn.tsx | 22 ++--- .../views/collections/CollectionStackingView.tsx | 73 ++++---------- .../CollectionStackingViewFieldColumn.tsx | 23 +++-- .../views/collections/CollectionTreeView.tsx | 8 +- src/client/views/nodes/DocumentView.tsx | 7 +- src/client/views/nodes/EquationBox.tsx | 5 +- src/client/views/nodes/WebBox.tsx | 6 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 4 +- 16 files changed, 136 insertions(+), 166 deletions(-) (limited to 'src/client/views/nodes/formattedText/FormattedTextBox.tsx') diff --git a/src/Utils.ts b/src/Utils.ts index e8bd35ac4..38325a463 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -902,6 +902,13 @@ export function setupMoveUpEvents( document.addEventListener('click', _clickEvent, true); } +export function DivHeight(ele: HTMLElement): number { + return Number(getComputedStyle(ele).height.replace('px', '')); +} +export function DivWidth(ele: HTMLElement): number { + return Number(getComputedStyle(ele).width.replace('px', '')); +} + export function dateRangeStrToDates(dateStr: string) { // dateStr in yyyy-mm-dd format const dateRangeParts = dateStr.split('|'); // splits into from and to date diff --git a/src/client/views/ContextMenu.tsx b/src/client/views/ContextMenu.tsx index 8c3c9df2e..8f4e43978 100644 --- a/src/client/views/ContextMenu.tsx +++ b/src/client/views/ContextMenu.tsx @@ -7,6 +7,7 @@ import { SettingsManager } from '../util/SettingsManager'; import './ContextMenu.scss'; import { ContextMenuItem, ContextMenuProps, OriginalMenuProps } from './ContextMenuItem'; import { ObservableReactComponent } from './ObservableReactComponent'; +import { DivHeight, DivWidth } from '../../Utils'; @observer export class ContextMenu extends ObservableReactComponent<{}> { @@ -214,8 +215,8 @@ export class ContextMenu extends ObservableReactComponent<{}> { className="contextMenu-cont" ref={action((r: any) => { if (r) { - this._width = Number(getComputedStyle(r).width.replace('px', '')); - this._height = Number(getComputedStyle(r).height.replace('px', '')); + this._width = DivWidth(r); + this._height = DivHeight(r); } })} style={{ diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 9d53c58c0..87ee962a0 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -562,7 +562,13 @@ export class DocumentDecorations extends ObservableReactComponent NumCast(doc._height) < 20 && (doc._layout_autoHeight = true)); + SelectionManager.Views.forEach(view => NumCast(view.Document._height) < 20 && (view.layoutDoc._layout_autoHeight = true)); //need to change points for resize, or else rotation/control points will fail. this._inkDragDocs .map(oldbds => ({ oldbds, inkPts: Cast(oldbds.doc.data, InkField)?.inkData || [] })) diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx index cb38ab602..3cb835e39 100644 --- a/src/client/views/PropertiesButtons.tsx +++ b/src/client/views/PropertiesButtons.tsx @@ -486,8 +486,7 @@ export class PropertiesButtons extends React.Component<{}, {}> { const isImage = layoutField instanceof ImageField; const isMap = this.selectedDoc?.type === DocumentType.MAP; const isCollection = this.selectedDoc?.type === DocumentType.COL; - //TODO: will likely need to create separate note-taking view type here - const isStacking = this.selectedDoc?._type_collection === CollectionViewType.Stacking || this.selectedDoc?._type_collection === CollectionViewType.NoteTaking; + const isStacking = [CollectionViewType.Stacking, CollectionViewType.Masonry, CollectionViewType.NoteTaking].includes(this.selectedDoc?._type_collection as any); const isFreeForm = this.selectedDoc?._type_collection === CollectionViewType.Freeform; const isTree = this.selectedDoc?._type_collection === CollectionViewType.Tree; const isTabView = this.selectedTabView; diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index d9d6a5eb5..8f1633122 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -11,7 +11,7 @@ import { List } from '../../../fields/List'; import { ImageCast, NumCast, StrCast } from '../../../fields/Types'; import { ImageField } from '../../../fields/URLField'; import { GetEffectiveAcl, inheritParentAcls } from '../../../fields/util'; -import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, incrementTitleCopy } from '../../../Utils'; +import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, DivHeight, DivWidth, emptyFunction, incrementTitleCopy } from '../../../Utils'; import { DocServer } from '../../DocServer'; import { Docs } from '../../documents/Documents'; import { CollectionViewType, DocumentType } from '../../documents/DocumentTypes'; @@ -432,8 +432,8 @@ export class CollectionDockingView extends CollectionSubView() { public CaptureThumbnail() { const content = this.DocumentView?.()?.ContentDiv; if (content) { - const _width = Number(getComputedStyle(content).width.replace('px', '')); - const _height = Number(getComputedStyle(content).height.replace('px', '')); + const _width = DivWidth(content); + const _height = DivHeight(content); return CollectionFreeFormView.UpdateIcon(this.layoutDoc[Id] + '-icon' + new Date().getTime(), content, _width, _height, _width, _height, 0, 1, true, this.layoutDoc[Id] + '-icon', (iconFile, _nativeWidth, _nativeHeight) => { const proto = this.dataDoc; // Cast(img.proto, Doc, null)!; proto['thumb_nativeWidth'] = _width; diff --git a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx index 41c5d5b42..763d2e3a6 100644 --- a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx +++ b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx @@ -33,8 +33,7 @@ interface CMVFieldRowProps { createDropTarget: (ele: HTMLDivElement) => void; screenToLocalTransform: () => Transform; setDocHeight: (key: string, thisHeight: number) => void; - observeHeight: (myref: any) => void; - unobserveHeight: (myref: any) => void; + refList: any[]; showHandle: boolean; } @@ -68,20 +67,20 @@ export class CollectionMasonryViewFieldRow extends ObservableReactComponent { this._dropDisposer?.(); - if (ele) { - this._ele = ele; - this._props.observeHeight(ele); - this._dropDisposer = DragManager.MakeDropTarget(ele, this.rowDrop.bind(this), this._props.Document); - } + if (ele) this._dropDisposer = DragManager.MakeDropTarget(ele, this.rowDrop.bind(this), this._props.Document); + else if (this._ele) this.props.refList.splice(this.props.refList.indexOf(this._ele), 1); + this._ele = ele; }; @action componentDidMount() { this.heading = this._props.headingObject?.heading || ''; this.color = this._props.headingObject?.color || '#f1efeb'; this.collapsed = this._props.headingObject?.collapsed || false; + this._ele && this.props.refList.push(this._ele); } componentWillUnmount() { - this._props.unobserveHeight(this._ele); + this._ele && this.props.refList.splice(this.props.refList.indexOf(this._ele), 1); + this._ele = null; } getTrueHeight = () => { diff --git a/src/client/views/collections/CollectionNoteTakingView.scss b/src/client/views/collections/CollectionNoteTakingView.scss index 91a82d40f..4c2dcf9ab 100644 --- a/src/client/views/collections/CollectionNoteTakingView.scss +++ b/src/client/views/collections/CollectionNoteTakingView.scss @@ -98,6 +98,7 @@ overflow: auto; display: flex; flex-direction: column; + height: max-content; } .collectionSchemaView-previewDoc { diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx index b8133806f..6318620e0 100644 --- a/src/client/views/collections/CollectionNoteTakingView.tsx +++ b/src/client/views/collections/CollectionNoteTakingView.tsx @@ -1,4 +1,4 @@ -import { action, computed, IReactionDisposer, makeObservable, observable, reaction } from 'mobx'; +import { action, computed, IReactionDisposer, makeObservable, observable, observe, reaction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { Doc, Field, Opt } from '../../../fields/Doc'; @@ -9,7 +9,7 @@ import { listSpec } from '../../../fields/Schema'; import { SchemaHeaderField } from '../../../fields/SchemaHeaderField'; import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../fields/Types'; import { TraceMobx } from '../../../fields/util'; -import { emptyFunction, returnFalse, returnZero, smoothScroll, Utils } from '../../../Utils'; +import { DivHeight, emptyFunction, returnFalse, returnZero, smoothScroll, Utils } from '../../../Utils'; import { Docs, DocUtils } from '../../documents/Documents'; import { DragManager, dropActionType } from '../../util/DragManager'; import { SnappingManager } from '../../util/SnappingManager'; @@ -45,6 +45,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { public DividerWidth = 16; @observable docsDraggedRowCol: number[] = []; @observable _scroll = 0; + @observable _refList: any[] = []; constructor(props: any) { super(props); @@ -157,8 +158,16 @@ export class CollectionNoteTakingView extends CollectionSubView() { document.addEventListener('pointerup', this.removeDocDragHighlight, true); this._disposers.layout_autoHeight = reaction( () => this.layoutDoc._layout_autoHeight, - layout_autoHeight => - layout_autoHeight && this._props.setHeight?.(Math.min(NumCast(this.layoutDoc._maxHeight, Number.MAX_SAFE_INTEGER), this.headerMargin + Math.max(...this.refList.map(r => Number(getComputedStyle(r).height.replace('px', '')))))) + layout_autoHeight => layout_autoHeight && this._props.setHeight?.(this.headerMargin + Math.max(...this._refList.map(DivHeight))) + ); + + this._disposers.refList = reaction( + () => ({ refList: this._refList.slice(), autoHeight: this.layoutDoc._layout_autoHeight && !LightboxView.Contains(this.DocumentView?.()) }), + ({ refList, autoHeight }) => { + if (autoHeight) refList.forEach(r => this.observer.observe(r)); + else this.observer.disconnect(); + }, + { fireImmediately: true } ); } @@ -345,7 +354,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { // get the index for where you need to insert the doc you are currently dragging const clientY = this.ScreenToLocalBoxXf().transformPoint(ex, ey)[1]; let dropInd = -1; - let pos0 = (this.refList.lastElement() as HTMLDivElement).children[0].getBoundingClientRect().height + this.yMargin * 2; + let pos0 = (this._refList.lastElement() as HTMLDivElement).children[0].getBoundingClientRect().height + this.yMargin * 2; colDocs.forEach((doc, i) => { let pos1 = this.getDocHeight(doc) + 2 * this.gridGap; pos1 += pos0; @@ -424,7 +433,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { if (super.onInternalDrop(e, de)) { // filter out the currently dragged docs from the child docs, since we will insert them later const rowCol = this.docsDraggedRowCol; - const droppedDocs = this.childDocs.slice().filter((d: Doc, ind: number) => ind >= this.childDocs.length); // if the drop operation adds something to the end of the list, then use that as the new document (may be different than what was dropped e.g., in the case of a button which is dropped but which creates say, a note). + const droppedDocs = this.childDocs.filter((d: Doc, ind: number) => ind >= this.childDocs.length); // if the drop operation adds something to the end of the list, then use that as the new document (may be different than what was dropped e.g., in the case of a button which is dropped but which creates say, a note). const newDocs = droppedDocs.length ? droppedDocs : de.complete.docDragData.droppedDocuments; const docs = this.childDocList; if (docs && newDocs.length) { @@ -489,65 +498,45 @@ export class CollectionNoteTakingView extends CollectionSubView() { headings = () => Array.from(this.Sections); - refList: any[] = []; - editableViewProps = () => ({ GetValue: () => '', SetValue: this.addGroup, contents: '+ New Column', }); + refList = () => this._refList; + // sectionNoteTaking returns a CollectionNoteTakingViewColumn (which is an individual column) - sectionNoteTaking = (heading: SchemaHeaderField | undefined, docList: Doc[]) => { - const type = 'number'; - return ( - this.refList.splice(this.refList.indexOf(ref), 1)} - observeHeight={ref => { - if (ref) { - this.refList.push(ref); - this.observer = new _global.ResizeObserver( - action((entries: any) => { - if (this.layoutDoc._layout_autoHeight && ref && this.refList.length && !SnappingManager.IsDragging) { - const height = this.headerMargin + Math.min(NumCast(this.layoutDoc._maxHeight, Number.MAX_SAFE_INTEGER), Math.max(...this.refList.map(r => Number(getComputedStyle(r).height.replace('px', ''))))); - if (!LightboxView.Contains(this.DocumentView?.())) { - this._props.setHeight?.(height); - } - } - }) - ); - this.observer.observe(ref); - } - }} - PanelWidth={this._props.PanelWidth} - select={this._props.select} - addDocument={this.addDocument} - chromeHidden={this.chromeHidden} - colHeaderData={this.colHeaderData} - Document={this.Document} - TemplateDataDocument={this._props.TemplateDataDocument} - resizeColumns={this.resizeColumns} - renderChildren={this.children} - numGroupColumns={this.numGroupColumns} - gridGap={this.gridGap} - pivotField={this.notetakingCategoryField} - fieldKey={this.fieldKey} - dividerWidth={this.DividerWidth} - maxColWidth={this.maxColWidth} - availableWidth={this.availableWidth} - headings={this.headings} - heading={heading?.heading ?? 'unset'} - headingObject={heading} - docList={docList} - yMargin={this.yMargin} - type={type} - createDropTarget={this.createDashEventsTarget} - screenToLocalTransform={this.ScreenToLocalBoxXf} - editableViewProps={this.editableViewProps} - /> - ); - }; + sectionNoteTaking = (heading: SchemaHeaderField | undefined, docList: Doc[]) => ( + + ); // addGroup is called when adding a new columnHeader, adding a SchemaHeaderField to our list of // columnHeaders and resizing the existing columns to make room for our new one. @@ -619,7 +608,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { return this.isContentActive() === false ? 'none' : undefined; } - observer: any; + observer = new _global.ResizeObserver(() => this._props.setHeight?.(this.headerMargin + Math.max(...this._refList.map(DivHeight)))); render() { TraceMobx(); diff --git a/src/client/views/collections/CollectionNoteTakingViewColumn.tsx b/src/client/views/collections/CollectionNoteTakingViewColumn.tsx index 38846c79d..db178d500 100644 --- a/src/client/views/collections/CollectionNoteTakingViewColumn.tsx +++ b/src/client/views/collections/CollectionNoteTakingViewColumn.tsx @@ -36,15 +36,13 @@ interface CSVFieldColumnProps { yMargin: number; numGroupColumns: number; gridGap: number; - type: 'string' | 'number' | 'bigint' | 'boolean' | 'symbol' | 'undefined' | 'object' | 'function' | undefined; headings: () => object[]; select: (ctrlPressed: boolean) => void; renderChildren: (docs: Doc[]) => JSX.Element[]; addDocument: (doc: Doc | Doc[]) => boolean; createDropTarget: (ele: HTMLDivElement) => void; screenToLocalTransform: () => Transform; - observeHeight: (myref: any) => void; - unobserveHeight: (myref: any) => void; + refList: any[]; editableViewProps: () => any; resizeColumns: (headers: SchemaHeaderField[]) => boolean; maxColWidth: number; @@ -78,15 +76,18 @@ export class CollectionNoteTakingViewColumn extends ObservableReactComponent { this.dropDisposer?.(); - if (ele) { - this._ele = ele; - this._props.observeHeight(ele); - this.dropDisposer = DragManager.MakeDropTarget(ele, this.columnDrop.bind(this), this._props.Document); - } + if (ele) this.dropDisposer = DragManager.MakeDropTarget(ele, this.columnDrop.bind(this), this._props.Document); + else if (this._ele) this.props.refList.slice(this.props.refList.indexOf(this._ele), 1); + this._ele = ele; }; + componentDidMount(): void { + this._ele && this.props.refList.push(this._ele); + } + componentWillUnmount() { - this._props.unobserveHeight(this._ele); + this._ele && this.props.refList.splice(this._props.refList.indexOf(this._ele), 1); + this._ele = null; } @undoBatch @@ -289,11 +290,10 @@ export class CollectionNoteTakingViewColumn extends ObservableReactComponent>() { + _disposers: { [key: string]: IReactionDisposer } = {}; _masonryGridRef: HTMLDivElement | null = null; // used in a column dragger, likely due for the masonry grid view. We want to use this _draggerRef = React.createRef(); - // Not sure what a pivot field is. Seems like we cause reaction in MobX get rid of it once we exit this view - _pivotFieldDisposer?: IReactionDisposer; - // Seems like we cause reaction in MobX get rid of our height once we exit this view - _layout_autoHeightDisposer?: IReactionDisposer; // keeping track of documents. Updated on internal and external drops. What's the difference? _docXfs: { height: () => number; width: () => number; stackedDocTransform: () => Transform }[] = []; // Doesn't look like this field is being used anywhere. Obsolete? _columnStart: number = 0; + + @observable _refList: any[] = []; // map of node headers to their heights. Used in Masonry @observable _heightMap = new Map(); // Assuming that this is the current css cursor style @@ -207,27 +205,27 @@ export class CollectionStackingView extends CollectionSubView this.pivotField, () => (this.dataDoc['_' + this.fieldKey + '_columnHeaders'] = new List()) ); - this._layout_autoHeightDisposer = reaction( + this._disposers.autoHeight = reaction( () => this.layoutDoc._layout_autoHeight, - layout_autoHeight => - layout_autoHeight && - this._props.setHeight?.( - Math.min( - NumCast(this.layoutDoc._maxHeight, Number.MAX_SAFE_INTEGER), - this.headerMargin + (this.isStackingView ? Math.max(...this.refList.map(r => Number(getComputedStyle(r).height.replace('px', '')))) : this.refList.reduce((p, r) => p + Number(getComputedStyle(r).height.replace('px', '')), 0)) - ) - ) + layout_autoHeight => layout_autoHeight && this._props.setHeight?.(this.headerMargin + (this.isStackingView ? Math.max(...this._refList.map(DivHeight)) : this._refList.reduce((p, r) => p + DivHeight(r), 0))) + ); + this._disposers.refList = reaction( + () => ({ refList: this._refList.slice(), autoHeight: this.layoutDoc._layout_autoHeight && !LightboxView.Contains(this.DocumentView?.()) }), + ({ refList, autoHeight }) => { + this.observer.disconnect(); + if (autoHeight) refList.forEach(r => this.observer.observe(r)); + }, + { fireImmediately: true } ); } componentWillUnmount() { super.componentWillUnmount(); - this._pivotFieldDisposer?.(); - this._layout_autoHeightDisposer?.(); + Object.keys(this._disposers).forEach(key => this._disposers[key]()); } isAnyChildContentActive = () => this._props.isAnyChildContentActive(); @@ -523,7 +521,6 @@ export class CollectionStackingView extends CollectionSubView Array.from(this.Sections); - refList: any[] = []; // what a section looks like if we're in stacking view sectionStacking = (heading: SchemaHeaderField | undefined, docList: Doc[]) => { const key = this.pivotField; @@ -536,23 +533,7 @@ export class CollectionStackingView extends CollectionSubView this.refList.splice(this.refList.indexOf(ref), 1)} - observeHeight={ref => { - if (ref) { - this.refList.push(ref); - this.observer = new _global.ResizeObserver( - action((entries: any) => { - if (this.layoutDoc._layout_autoHeight && ref && this.refList.length && !SnappingManager.IsDragging) { - const height = this.headerMargin + Math.min(NumCast(this.layoutDoc._maxHeight, Number.MAX_SAFE_INTEGER), Math.max(...this.refList.map(r => Number(getComputedStyle(r).height.replace('px', ''))))); - if (!LightboxView.Contains(this.DocumentView?.())) { - this._props.setHeight?.(height); - } - } - }) - ); - this.observer.observe(ref); - } - }} + refList={this._refList} addDocument={this.addDocument} chromeHidden={this.chromeHidden} colHeaderData={this.colHeaderData} @@ -591,21 +572,7 @@ export class CollectionStackingView extends CollectionSubView this.refList.splice(this.refList.indexOf(ref), 1)} - observeHeight={ref => { - if (ref) { - this.refList.push(ref); - this.observer = new _global.ResizeObserver( - action((entries: any) => { - if (this.layoutDoc._layout_autoHeight && ref && this.refList.length && !SnappingManager.IsDragging) { - const height = this.refList.reduce((p, r) => p + Number(getComputedStyle(r).height.replace('px', '')), 0); - this._props.setHeight?.(2 * this.headerMargin + height); // bcz: added 2x for header to fix problem with scrollbars appearing in Tools panel - } - }) - ); - this.observer.observe(ref); - } - }} + refList={this._refList} key={heading ? heading.heading : ''} rows={rows} headings={this.headings} @@ -709,7 +676,9 @@ export class CollectionStackingView extends CollectionSubView this._props.setHeight?.(this.headerMargin + (this.isStackingView ? Math.max(...this._refList.map(DivHeight)) : this._refList.reduce((p, r) => p + DivHeight(r), 0)))); + render() { TraceMobx(); const editableViewProps = { diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx index c455f20d8..6a3cb759e 100644 --- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx +++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx @@ -9,7 +9,7 @@ import { ScriptField } from '../../../fields/ScriptField'; import { BoolCast, NumCast } from '../../../fields/Types'; import { ImageField } from '../../../fields/URLField'; import { TraceMobx } from '../../../fields/util'; -import { emptyFunction, returnEmptyString, setupMoveUpEvents } from '../../../Utils'; +import { DivHeight, DivWidth, emptyFunction, returnEmptyString, setupMoveUpEvents } from '../../../Utils'; import { Docs, DocUtils } from '../../documents/Documents'; import { DocumentType } from '../../documents/DocumentTypes'; import { DragManager } from '../../util/DragManager'; @@ -44,8 +44,7 @@ interface CSVFieldColumnProps { addDocument: (doc: Doc | Doc[]) => boolean; createDropTarget: (ele: HTMLDivElement) => void; screenToLocalTransform: () => Transform; - observeHeight: (myref: any) => void; - unobserveHeight: (myref: any) => void; + refList: any[]; } @observer @@ -53,7 +52,7 @@ export class CollectionStackingViewFieldColumn extends ObservableReactComponent< private dropDisposer?: DragManager.DragDropDisposer; private _disposers: { [name: string]: IReactionDisposer } = {}; private _headerRef: React.RefObject = React.createRef(); - @observable private _background = 'inherit'; + @observable _background = 'inherit'; @observable _paletteOn = false; @observable _heading = ''; @observable _color = ''; @@ -71,15 +70,14 @@ export class CollectionStackingViewFieldColumn extends ObservableReactComponent< // is that the only way to have drop targets? createColumnDropRef = (ele: HTMLDivElement | null) => { this.dropDisposer?.(); - if (ele) { - this._ele = ele; - this._props.observeHeight(ele); - this.dropDisposer = DragManager.MakeDropTarget(ele, this.columnDrop.bind(this), this._props.Document); - } + if (ele) this.dropDisposer = DragManager.MakeDropTarget(ele, this.columnDrop.bind(this), this._props.Document); + else if (this._ele) this.props.refList.splice(this.props.refList.indexOf(this._ele), 1); + this._ele = ele; }; @action componentDidMount() { + this._ele && this.props.refList.push(this._ele); this._disposers.collapser = reaction( () => this._props.headingObject?.collapsed, collapsed => (this.collapsed = collapsed !== undefined ? BoolCast(collapsed) : false), @@ -88,7 +86,8 @@ export class CollectionStackingViewFieldColumn extends ObservableReactComponent< } componentWillUnmount() { this._disposers.collapser?.(); - this._props.unobserveHeight(this._ele); + this._ele && this.props.refList.splice(this.props.refList.indexOf(this._ele), 1); + this._ele = null; } //TODO: what is scripting? I found it in SetInPlace def but don't know what that is @@ -217,8 +216,8 @@ export class CollectionStackingViewFieldColumn extends ObservableReactComponent< const layoutItems: ContextMenuProps[] = []; const docItems: ContextMenuProps[] = []; const dataDoc = this._props.TemplateDataDocument || this._props.Document; - const width = this._ele ? Number(getComputedStyle(this._ele).width.replace('px', '')) : 0; - const height = this._ele ? Number(getComputedStyle(this._ele).height.replace('px', '')) : 0; + const width = this._ele ? DivWidth(this._ele) : 0; + const height = this._ele ? DivHeight(this._ele) : 0; DocUtils.addDocumentCreatorMenuItems( doc => { FormattedTextBox.SetSelectOnLoad(doc); diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 4d60cbefc..3b37bdcfa 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -8,7 +8,7 @@ import { listSpec } from '../../../fields/Schema'; import { ScriptField } from '../../../fields/ScriptField'; import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../fields/Types'; import { TraceMobx } from '../../../fields/util'; -import { emptyFunction, returnAll, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnNone, returnOne, returnTrue, returnZero, Utils } from '../../../Utils'; +import { DivHeight, emptyFunction, returnAll, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnNone, returnOne, returnTrue, returnZero, Utils } from '../../../Utils'; import { Docs, DocUtils } from '../../documents/Documents'; import { DocumentManager } from '../../util/DocumentManager'; import { DragManager, dropActionType } from '../../util/DragManager'; @@ -113,8 +113,8 @@ export class CollectionTreeView extends CollectionSubView { if (!this._isDisposing) { - const titleHeight = !this._titleRef ? this.marginTop() : Number(getComputedStyle(this._titleRef).height.replace('px', '')); - const bodyHeight = Array.from(this.refList).reduce((p, r) => p + Number(getComputedStyle(r).height.replace('px', '')), this.marginBot()) + 6; + const titleHeight = !this._titleRef ? this.marginTop() : DivHeight(this._titleRef); + const bodyHeight = Array.from(this.refList).reduce((p, r) => p + DivHeight(r), this.marginBot()) + 6; this.layoutDoc._layout_autoHeightMargins = bodyHeight; !this._props.dontRegisterView && this._props.setHeight?.(bodyHeight + titleHeight); } @@ -420,7 +420,7 @@ export class CollectionTreeView extends CollectionSubView {!this.buttonMenu && !this.noviceExplainer ? null : ( -
r && (this._headerHeight = Number(getComputedStyle(r).height.replace(/px/, ''))))}> +
r && (this._headerHeight = DivHeight(r)))}> {this.buttonMenu} {this.noviceExplainer}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index b0e8cf6ff..ee058c085 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -1,11 +1,10 @@ import { IconProp } from '@fortawesome/fontawesome-svg-core'; -import { Dropdown, DropdownType, Type } from 'browndash-components'; import { Howl } from 'howler'; import { IReactionDisposer, action, computed, makeObservable, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { Bounce, Fade, Flip, JackInTheBox, Roll, Rotate, Zoom } from 'react-awesome-reveal'; -import { Utils, emptyFunction, isTargetChildOf as isParentOf, lightOrDark, returnEmptyString, returnFalse, returnTrue, returnVal, simulateMouseClick } from '../../../Utils'; +import { DivWidth, Utils, emptyFunction, isTargetChildOf as isParentOf, lightOrDark, returnEmptyString, returnFalse, returnTrue, returnVal, simulateMouseClick } from '../../../Utils'; import { Doc, DocListCast, Field, Opt, StrListCast } from '../../../fields/Doc'; import { AclPrivate, Animation, AudioPlay, DocData, DocViews } from '../../../fields/DocSymbols'; import { Id } from '../../../fields/FieldSymbols'; @@ -703,7 +702,7 @@ export class DocumentViewInternal extends DocComponent this._props.PanelHeight() - this.headerMargin; screenToLocalContent = () => this._props.ScreenToLocalTransform().translate(0, -this.headerMargin); onClickFunc = this.disableClickScriptFunc ? undefined : () => this.onClickHandler; - setHeight = (height: number) => !this._props.suppressSetHeight && (this.layoutDoc._height = height); + setHeight = (height: number) => !this._props.suppressSetHeight && (this.layoutDoc._height = Math.min(NumCast(this.layoutDoc._maxHeight, Number.MAX_SAFE_INTEGER), height)); setContentView = action((view: ViewBoxInterface) => (this._componentView = view)); isContentActive = (): boolean | undefined => this._isContentActive; childFilters = () => [...this._props.childFilters(), ...StrListCast(this.layoutDoc.childFilters)]; @@ -788,7 +787,7 @@ export class DocumentViewInternal extends DocComponent { return (
r && (this._titleDropDownInnerWidth = Number(getComputedStyle(r).width.replace('px', ''))))} + ref={action((r: any) => r && (this._titleDropDownInnerWidth = DivWidth(r)))} onPointerDown={action(e => (this._changingTitleField = true))} style={{ width: 'max-content', background: SettingsManager.userBackgroundColor, color: SettingsManager.userColor, transformOrigin: 'left', transform: `scale(${this.titleHeight / 30 /* height of Dropdown */})` }}> () { @@ -57,8 +58,8 @@ export class EquationBox extends ViewBoxBaseComponent() { @action keyPressed = (e: KeyboardEvent) => { - const _height = Number(getComputedStyle(this._ref.current!.element.current).height.replace('px', '')); - const _width = Number(getComputedStyle(this._ref.current!.element.current).width.replace('px', '')); + const _height = DivHeight(this._ref.current!.element.current); + const _width = DivWidth(this._ref.current!.element.current); if (e.key === 'Enter') { const nextEq = Docs.Create.EquationDocument(e.shiftKey ? StrCast(this.dataDoc.text) : 'x', { title: '# math', diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 2c5398e40..c9340edc0 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -14,7 +14,7 @@ import { listSpec } from '../../../fields/Schema'; import { Cast, NumCast, StrCast, WebCast } from '../../../fields/Types'; import { ImageField, WebField } from '../../../fields/URLField'; import { TraceMobx } from '../../../fields/util'; -import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, getWordAtPoint, lightOrDark, returnFalse, returnOne, returnZero, setupMoveUpEvents, smoothScroll, stringHash, Utils } from '../../../Utils'; +import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, DivHeight, emptyFunction, getWordAtPoint, lightOrDark, returnFalse, returnOne, returnZero, setupMoveUpEvents, smoothScroll, stringHash, Utils } from '../../../Utils'; import { Docs, DocUtils } from '../../documents/Documents'; import { DocumentManager } from '../../util/DocumentManager'; import { ScriptingGlobals } from '../../util/ScriptingGlobals'; @@ -83,7 +83,7 @@ export class WebBox extends ViewBoxAnnotatableComponent() implem return this.webField?.toString() || ''; } @computed get _urlHash() { - return ""+ (stringHash(this._url)??''); + return '' + (stringHash(this._url) ?? ''); } @computed get scrollHeight() { return Math.max(NumCast(this.layoutDoc._height), this._scrollHeight); @@ -782,7 +782,7 @@ export class WebBox extends ViewBoxAnnotatableComponent() implem className="webBox-htmlSpan" ref={action((r: any) => { if (r) { - this._scrollHeight = Number(getComputedStyle(r).height.replace('px', '')); + this._scrollHeight = DivHeight(r); this.lighttext = Array.from(r.children).some((c: any) => c instanceof HTMLElement && lightOrDark(getComputedStyle(c).color) !== Colors.WHITE); } })} diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 56008de8e..266a2442f 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -23,7 +23,7 @@ import { RichTextField } from '../../../../fields/RichTextField'; import { ComputedField } from '../../../../fields/ScriptField'; import { BoolCast, Cast, DocCast, FieldValue, NumCast, ScriptCast, StrCast } from '../../../../fields/Types'; import { GetEffectiveAcl, TraceMobx } from '../../../../fields/util'; -import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, numberRange, returnFalse, returnZero, setupMoveUpEvents, smoothScroll, unimplementedFunction, Utils } from '../../../../Utils'; +import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, DivWidth, emptyFunction, numberRange, returnFalse, returnZero, setupMoveUpEvents, smoothScroll, unimplementedFunction, Utils } from '../../../../Utils'; import { gptAPICall, GPTCallType } from '../../../apis/gpt/GPT'; import { DocServer } from '../../../DocServer'; import { Docs, DocUtils } from '../../../documents/Documents'; @@ -758,7 +758,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { const defaultSidebar = 250; - const prevWidth = 1 - this.sidebarWidth() / Number(getComputedStyle(this._ref.current!).width.replace('px', '')); + const prevWidth = 1 - this.sidebarWidth() / DivWidth(this._ref.current!); if (preview) this._showSidebar = true; else { this.layoutDoc[this.SidebarKey + '_freeform_scale_max'] = 1; -- cgit v1.2.3-70-g09d2 From 11b6cb8344f26e5895bebc3dedef491675717e30 Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 5 Mar 2024 15:11:29 -0500 Subject: fixed text in templates to revert to template value when noTemplate is set. made dashFieldView read from datadoc. added margins for multicolumn/row, enabled chromHidden for multicolumn/row --- src/client/views/PropertiesView.tsx | 3 ++- .../collectionMulticolumn/CollectionMulticolumnView.tsx | 10 ++++++---- src/client/views/nodes/formattedText/DashFieldView.tsx | 15 +++++++-------- src/client/views/nodes/formattedText/FormattedTextBox.tsx | 5 +++-- 4 files changed, 18 insertions(+), 15 deletions(-) (limited to 'src/client/views/nodes/formattedText/FormattedTextBox.tsx') diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx index e4e7bec32..cbd3ff358 100644 --- a/src/client/views/PropertiesView.tsx +++ b/src/client/views/PropertiesView.tsx @@ -135,7 +135,7 @@ export class PropertiesView extends ObservableReactComponent (!this.selectedLayoutDoc ? 0 : Math.min(NumCast(this.selectedLayoutDoc?._width), this._props.width - 20)); @@ -1076,6 +1076,7 @@ export class PropertiesView extends ObservableReactComponent {!this.isStack ? null : this.getNumber('Gap', ' px', 0, 200, NumCast(this.selectedDoc!.gridGap), (val: number) => !isNaN(val) && (this.selectedDoc!.gridGap = val))} {!this.isStack ? null : this.getNumber('xMargin', ' px', 0, 500, NumCast(this.selectedDoc!.xMargin), (val: number) => !isNaN(val) && (this.selectedDoc!.xMargin = val))} + {!this.isStack ? null : this.getNumber('yMargin', ' px', 0, 500, NumCast(this.selectedDoc!.yMargin), (val: number) => !isNaN(val) && (this.selectedDoc!.yMargin = val))} {!this.isGroup ? null : this.getNumber('Padding', ' px', 0, 500, NumCast(this.selectedDoc!.xPadding), (val: number) => !isNaN(val) && (this.selectedDoc!.xPadding = this.selectedDoc!.yPadding = val))} {this.isInk ? this.controlPointsButton : null} {this.getNumber('Width', ' px', 0, Math.max(1000, this.shapeWid), this.shapeWid, (val: number) => !isNaN(val) && (this.shapeWid = val), 1000, 1)} diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx index 85fe7c896..125dd2781 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx @@ -315,7 +315,9 @@ export class CollectionMulticolumnView extends CollectionSubView() {
{this.getDisplayDoc(layout)} -
, @@ -350,14 +352,14 @@ export class CollectionMulticolumnView extends CollectionSubView() { }}> {this.contents} {!this._startIndex ? null : ( - +
(this._startIndex = Math.min(this.childLayoutPairs.length - 1, this._startIndex + this.maxShown)))}>
)} - {this._startIndex > this.childLayoutPairs.length - 1 ? null : ( - + {this._startIndex > this.childLayoutPairs.length - 1 || !this.maxShown ? null : ( +
(this._startIndex = Math.min(this.childLayoutPairs.length - 1, this._startIndex + this.maxShown)))}> } color={SettingsManager.userColor} />
diff --git a/src/client/views/nodes/formattedText/DashFieldView.tsx b/src/client/views/nodes/formattedText/DashFieldView.tsx index b49e7dcf0..5c4d850ad 100644 --- a/src/client/views/nodes/formattedText/DashFieldView.tsx +++ b/src/client/views/nodes/formattedText/DashFieldView.tsx @@ -4,24 +4,23 @@ import { action, computed, IReactionDisposer, makeObservable, observable, reacti import { observer } from 'mobx-react'; import * as React from 'react'; import * as ReactDOM from 'react-dom/client'; -import Select from 'react-select'; import { Doc, DocListCast, Field } from '../../../../fields/Doc'; import { List } from '../../../../fields/List'; import { listSpec } from '../../../../fields/Schema'; import { SchemaHeaderField } from '../../../../fields/SchemaHeaderField'; -import { Cast, StrCast } from '../../../../fields/Types'; +import { Cast } from '../../../../fields/Types'; import { emptyFunction, returnFalse, returnZero, setupMoveUpEvents } from '../../../../Utils'; import { DocServer } from '../../../DocServer'; import { CollectionViewType } from '../../../documents/DocumentTypes'; import { Transform } from '../../../util/Transform'; -import { undoable, undoBatch } from '../../../util/UndoManager'; +import { undoBatch } from '../../../util/UndoManager'; import { AntimodeMenu, AntimodeMenuProps } from '../../AntimodeMenu'; import { SchemaTableCell } from '../../collections/collectionSchema/SchemaTableCell'; +import { FilterPanel } from '../../FilterPanel'; import { ObservableReactComponent } from '../../ObservableReactComponent'; import { OpenWhere } from '../DocumentView'; import './DashFieldView.scss'; import { FormattedTextBox } from './FormattedTextBox'; -import { FilterPanel } from '../../FilterPanel'; export class DashFieldView { dom: HTMLDivElement; // container for label and value @@ -29,7 +28,7 @@ export class DashFieldView { node: any; tbox: FormattedTextBox; - unclickable = () => !this.tbox._props.isSelected() && this.node.marks.some((m: any) => m.type === this.tbox.EditorView?.state.schema.marks.linkAnchor && m.attrs.noPreview); + unclickable = () => !this.tbox._props.rootSelected?.() && this.node.marks.some((m: any) => m.type === this.tbox.EditorView?.state.schema.marks.linkAnchor && m.attrs.noPreview); constructor(node: any, view: any, getPos: any, tbox: FormattedTextBox) { this.node = node; this.tbox = tbox; @@ -108,12 +107,12 @@ export class DashFieldViewInternal extends ObservableReactComponent dashDoc instanceof Doc && (this._dashDoc = dashDoc))); } else { - this._dashDoc = this._props.tbox.Document; + this._dashDoc = this._fieldKey.startsWith('_') ? this._props.tbox.Document : this._props.tbox.dataDoc; } } @@ -202,7 +201,7 @@ export class DashFieldViewInternal extends ObservableReactComponent {this._props.hideKey ? null : ( diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 266a2442f..2d5239f06 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -374,9 +374,10 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent Date: Wed, 6 Mar 2024 12:28:24 -0500 Subject: cleaned up some dropActionType strings. fixed stackingview scrolling when always active. fixed schemaView keys dropdown menu to be a popup. cleaned up display of key Finfo's --- src/client/documents/Documents.ts | 46 +++---- src/client/views/DashboardView.tsx | 9 +- src/client/views/TemplateMenu.tsx | 2 +- .../views/collections/CollectionStackingView.tsx | 15 ++- src/client/views/collections/CollectionSubView.tsx | 5 +- src/client/views/collections/TreeView.tsx | 6 +- .../collectionSchema/CollectionSchemaView.scss | 149 +++++++++++---------- .../collectionSchema/CollectionSchemaView.tsx | 68 ++++++---- src/client/views/nodes/LinkAnchorBox.tsx | 4 +- .../views/nodes/RecordingBox/RecordingBox.tsx | 4 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 4 +- 11 files changed, 170 insertions(+), 142 deletions(-) (limited to 'src/client/views/nodes/formattedText/FormattedTextBox.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 031560886..c9b5cb915 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -70,14 +70,14 @@ class EmptyBox { } export enum FInfoFieldType { - string, - boolean, - number, - Doc, - enumeration, - date, - list, - rtf, + string = 'string', + boolean = 'boolean', + number = 'number', + Doc = 'Doc', + enumeration = 'enum', + date = 'date', + list = 'list', + rtf = 'rich text', } export class FInfo { description: string = ''; @@ -198,20 +198,20 @@ type DATEt = DateInfo | number; type DTYPEt = DTypeInfo | string; export class DocumentOptions { // coordinate and dimensions depending on view - x?: NUMt = new NumInfo('x coordinate of document in a freeform view', false); - y?: NUMt = new NumInfo('y coordinate of document in a freeform view', false); + x?: NUMt = new NumInfo('horizontal coordinate in freeform view', false); + y?: NUMt = new NumInfo('vertical coordinate in freeform view', false); z?: NUMt = new NumInfo('whether document is in overlay (1) or not (0)', false, false, [1, 0]); - overlayX?: NUMt = new NumInfo('x coordinate of document in a overlay view', false); - overlayY?: NUMt = new NumInfo('y coordinate of document in a overlay view', false); - text?: RTFt = new RtfInfo('rich text of a text doc', true); + overlayX?: NUMt = new NumInfo('horizontal coordinate in overlay view', false); + overlayY?: NUMt = new NumInfo('vertical coordinate in overlay view', false); + text?: RTFt = new RtfInfo('plain or rich text', true); _dimMagnitude?: NUMt = new NumInfo("magnitude of collectionMulti{row,col} element's width or height", false); _dimUnit?: DIMt = new DimInfo("units of collectionMulti{row,col} element's width or height - 'px' or '*' for pixels or relative units"); - latitude?: NUMt = new NumInfo('latitude coordinate for map views', false); - longitude?: NUMt = new NumInfo('longitude coordinate for map views', false); + latitude?: NUMt = new NumInfo('latitude coordinate', false); + longitude?: NUMt = new NumInfo('longitude coordinate', false); routeCoordinates?: STRt = new StrInfo("stores a route's/direction's coordinates (stringified version)"); // for a route document, this stores the route's coordinates - markerType?: STRt = new StrInfo('Defines the marker type for a pushpin document'); - markerColor?: STRt = new StrInfo('Defines the marker color for a pushpin document'); - map?: STRt = new StrInfo('text location of map'); + markerType?: STRt = new StrInfo('marker type for a pushpin document'); + markerColor?: STRt = new StrInfo('marker color for a pushpin document'); + map?: STRt = new StrInfo('map location name'); map_type?: STRt = new StrInfo('type of map view', false); map_zoom?: NUMt = new NumInfo('zoom of a map view', false); map_pitch?: NUMt = new NumInfo('pitch of a map view', false); @@ -221,11 +221,11 @@ export class DocumentOptions { date_range?: STRt = new StrInfo('date range for calendar', false); wikiData?: STRt = new StrInfo('WikiData ID related to map location'); - description?: STRt = new StrInfo('A description of the document'); - _timecodeToShow?: NUMt = new NumInfo('the time that a document should be displayed (e.g., when an annotation shows up as a video plays)', false); - _timecodeToHide?: NUMt = new NumInfo('the time that a document should be hidden', false); - _width?: NUMt = new NumInfo('displayed width of a document'); - _height?: NUMt = new NumInfo('displayed height of document'); + description?: STRt = new StrInfo('description of document'); + _timecodeToShow?: NUMt = new NumInfo('media timecode when document should appear (e.g., when an annotation shows up as a video plays)', false); + _timecodeToHide?: NUMt = new NumInfo('media timecode when document should disappear', false); + _width?: NUMt = new NumInfo("width of document in container's coordinates"); + _height?: NUMt = new NumInfo("height of document in container's coordiantes"); data_nativeWidth?: NUMt = new NumInfo('native width of data field contents (e.g., the pixel width of an image)', false); data_nativeHeight?: NUMt = new NumInfo('native height of data field contents (e.g., the pixel height of an image)', false); linearBtnWidth?: NUMt = new NumInfo('unexpanded width of a linear menu button (button "width" changes when it expands)', false); diff --git a/src/client/views/DashboardView.tsx b/src/client/views/DashboardView.tsx index 472d419fc..439d250de 100644 --- a/src/client/views/DashboardView.tsx +++ b/src/client/views/DashboardView.tsx @@ -28,6 +28,7 @@ import { Colors } from './global/globalEnums'; import { MainViewModal } from './MainViewModal'; import { ButtonType } from './nodes/FontIconBox/FontIconBox'; import { ObservableReactComponent } from './ObservableReactComponent'; +import { dropActionType } from '../util/DragManager'; enum DashboardGroup { MyDashboards, @@ -403,7 +404,7 @@ export class DashboardView extends ObservableReactComponent<{}> { _layout_fitWidth: true, _gridGap: 5, _forceActive: true, - childDragAction: 'embed', + childDragAction: dropActionType.embed, treeView_TruncateTitleWidth: 150, ignoreClick: true, contextMenuIcons: new List(['plus']), @@ -411,7 +412,7 @@ export class DashboardView extends ObservableReactComponent<{}> { _lockedPosition: true, layout_boxShadow: '0 0', childDontRegisterViews: true, - dropAction: 'same', + dropAction: dropActionType.same, isSystem: true, layout_explainer: 'All of the calendars that you have created will appear here.', }; @@ -450,7 +451,7 @@ export class DashboardView extends ObservableReactComponent<{}> { _layout_fitWidth: true, _gridGap: 5, _forceActive: true, - childDragAction: 'embed', + childDragAction: dropActionType.embed, treeView_TruncateTitleWidth: 150, ignoreClick: true, layout_headerButton: myTrailsBtn, @@ -459,7 +460,7 @@ export class DashboardView extends ObservableReactComponent<{}> { _lockedPosition: true, layout_boxShadow: '0 0', childDontRegisterViews: true, - dropAction: 'same', + dropAction: dropActionType.same, isSystem: true, layout_explainer: 'All of the trails that you have created will appear here.', }; diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx index 5d9abb460..00195f7d7 100644 --- a/src/client/views/TemplateMenu.tsx +++ b/src/client/views/TemplateMenu.tsx @@ -105,7 +105,7 @@ export class TemplateMenu extends React.Component { const addedTypes = DocListCast(Cast(Doc.UserDoc()['template_clickFuncs'], Doc, null)?.data); const templateMenu: Array = []; this.props.templates?.forEach((checked, template) => templateMenu.push()); - templateMenu.push(); + templateMenu.push(); addedTypes.concat(noteTypes).map(template => (template.treeView_Checked = this.templateIsUsed(firstDoc, template))); this._addedKeys && Array.from(this._addedKeys) diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index dc391631a..ea1caf58f 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -233,10 +233,6 @@ export class CollectionStackingView extends CollectionSubView boolean): boolean => { return this._props.removeDocument?.(doc) && addDocument?.(doc) ? true : false; }; - createRef = (ele: HTMLDivElement | null) => { - this._masonryGridRef = ele; - this.createDashEventsTarget(ele!); //so the whole grid is the drop target? - }; onChildClickHandler = () => this._props.childClickScript || ScriptCast(this.Document.onChildClick); @computed get onChildDoubleClickHandler() { @@ -679,6 +675,8 @@ export class CollectionStackingView extends CollectionSubView this._props.setHeight?.(this.headerMargin + (this.isStackingView ? Math.max(...this._refList.map(DivHeight)) : this._refList.reduce((p, r) => p + DivHeight(r), 0)))); + onPassiveWheel = (e: WheelEvent) => e.stopPropagation(); + _oldWheel: any; render() { TraceMobx(); const editableViewProps = { @@ -699,7 +697,14 @@ export class CollectionStackingView extends CollectionSubView
{ + this._masonryGridRef = ele; + this.createDashEventsTarget(ele); //so the whole grid is the drop target? + this._oldWheel?.removeEventListener('wheel', this.onPassiveWheel); + this._oldWheel = ele; + // prevent wheel events from passively propagating up through containers and prevents containers from preventDefault which would block scrolling + ele?.addEventListener('wheel', this.onPassiveWheel, { passive: false }); + }} style={{ overflowY: this.isContentActive() ? 'auto' : 'hidden', background: this._props.styleProvider?.(this.Document, this._props, StyleProp.BackgroundColor), diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index fdbd1cc90..59a695a3d 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -219,12 +219,13 @@ export function CollectionSubView(moreProps?: X) { const targetDocments = DocListCast(this.dataDoc[this._props.fieldKey]); const someMoved = !dropAction && docDragData.draggedDocuments.some(drag => targetDocments.includes(drag)); if (someMoved) docDragData.droppedDocuments = docDragData.droppedDocuments.map((drop, i) => (targetDocments.includes(docDragData.draggedDocuments[i]) ? docDragData.draggedDocuments[i] : drop)); - if ((!dropAction || dropAction === 'inSame' || dropAction === 'same' || dropAction === 'move' || someMoved) && docDragData.moveDocument) { + if ((!dropAction || dropAction === dropActionType.inPlace || dropAction === dropActionType.same || dropAction === dropActionType.move || someMoved) && docDragData.moveDocument) { const movedDocs = docDragData.droppedDocuments.filter((d, i) => docDragData.draggedDocuments[i] === d); const addedDocs = docDragData.droppedDocuments.filter((d, i) => docDragData.draggedDocuments[i] !== d); if (movedDocs.length) { const canAdd = - (de.embedKey || dropAction || Doc.AreProtosEqual(Cast(movedDocs[0].annotationOn, Doc, null), this.Document)) && (dropAction !== 'inSame' || docDragData.draggedDocuments.every(d => d.embedContainer === this.Document)); + (de.embedKey || dropAction || Doc.AreProtosEqual(Cast(movedDocs[0].annotationOn, Doc, null), this.Document)) && + (dropAction !== dropActionType.inPlace || docDragData.draggedDocuments.every(d => d.embedContainer === this.Document)); const moved = docDragData.moveDocument(movedDocs, this.Document, canAdd ? this.addDocument : returnFalse); added = canAdd || moved ? moved : undefined; } else if (addedDocs.length) { diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index 4f2d8b9c0..285a789e6 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -449,10 +449,10 @@ export class TreeView extends ObservableReactComponent { const addDoc = inside ? this.localAdd : parentAddDoc; const canAdd = !StrCast((inside ? this.Document : this._props.treeViewParent)?.treeView_FreezeChildren).includes('add') || forceAdd; - if (canAdd && (dropAction !== 'inSame' || droppedDocuments.every(d => d.embedContainer === this._props.parentTreeView?.Document))) { - const move = (!dropAction || canEmbed || dropAction === 'proto' || dropAction === 'move' || dropAction === 'same' || dropAction === 'inSame') && moveDocument; + if (canAdd && (dropAction !== dropActionType.inPlace || droppedDocuments.every(d => d.embedContainer === this._props.parentTreeView?.Document))) { + const move = (!dropAction || canEmbed || dropAction === dropActionType.proto || dropAction === dropActionType.move || dropAction === dropActionType.same || dropAction === dropActionType.inPlace) && moveDocument; this._props.parentTreeView instanceof TreeView && (this._props.parentTreeView.dropping = true); - const res = droppedDocuments.reduce((added, d) => (move ? move(d, undefined, addDoc) || (dropAction === 'proto' ? addDoc(d) : false) : addDoc(d)) || added, false); + const res = droppedDocuments.reduce((added, d) => (move ? move(d, undefined, addDoc) || (dropAction === dropActionType.proto ? addDoc(d) : false) : addDoc(d)) || added, false); this._props.parentTreeView instanceof TreeView && (this._props.parentTreeView.dropping = false); return res; } diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss index fed4e89cf..ac0bd2378 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss +++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss @@ -38,91 +38,97 @@ background: yellow; } } + } - .schema-column-menu, - .schema-filter-menu { - background: $light-gray; - position: absolute; - min-width: 200px; - max-width: 400px; - display: flex; - flex-direction: column; - align-items: flex-start; - z-index: 1; - - .schema-key-search-input { - width: calc(100% - 20px); - margin: 10px; - } + .schema-preview-divider { + height: 100%; + background: black; + cursor: ew-resize; + } +} - .schema-search-result { - cursor: pointer; - padding: 5px 10px; - width: 100%; +.schema-column-menu, +.schema-filter-menu { + background: $light-gray; + position: relative; + min-width: 200px; + max-width: 400px; + display: flex; + flex-direction: column; + align-items: flex-start; + z-index: 1; - &:hover { - background-color: $medium-gray; - } + .schema-key-search-input { + width: calc(100% - 20px); + margin: 10px; + } - .schema-search-result-type, - .schema-search-result-desc { - color: $dark-gray; - font-size: $body-text; - } - } + .schema-search-result { + cursor: pointer; + padding: 5px 10px; + width: 100%; - .schema-key-search, - .schema-new-key-options { - width: 100%; - display: flex; - flex-direction: column; - align-items: flex-start; - } + &:hover { + background-color: $medium-gray; + } + .schema-search-result-type { + font-family: 'Courier New', Courier, monospace; + } - .schema-new-key-options { - margin: 10px; - .schema-key-warning { - color: red; - font-weight: normal; - align-self: center; - } - } + .schema-search-result-type, + .schema-search-result-desc { + color: $dark-gray; + font-size: $body-text; + } + .schema-search-result-desc { + font-style: italic; + } + } - .schema-key-list { - width: 100%; - max-height: 300px; - overflow-y: auto; - } + .schema-key-search, + .schema-new-key-options { + width: 100%; + display: flex; + flex-direction: column; + align-items: flex-start; + } - .schema-key-type-option { - margin: 2px 0px; + .schema-new-key-options { + margin: 10px; + .schema-key-warning { + color: red; + font-weight: normal; + align-self: center; + } + } - input { - margin-right: 5px; - } - } + .schema-key-list { + width: 100%; + max-height: 300px; + overflow-y: auto; + } - .schema-key-default-val { - margin: 5px 0; - } + .schema-key-type-option { + margin: 2px 0px; - .schema-column-menu-button { - cursor: pointer; - padding: 2px 5px; - background: $medium-blue; - border-radius: 9999px; - color: $white; - width: fit-content; - margin: 5px; - align-self: center; - } + input { + margin-right: 5px; } } - .schema-preview-divider { - height: 100%; - background: black; - cursor: ew-resize; + .schema-key-default-val { + margin: 5px 0; + } + + .schema-column-menu-button { + cursor: pointer; + padding: 2px 5px; + background: $medium-blue; + border-radius: 9999px; + color: $white; + width: fit-content; + margin: 5px; + align-self: center; } } @@ -133,6 +139,7 @@ .row-menu { display: flex; justify-content: center; + cursor: pointer; } } diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx index eee3836d2..12f0ad5e9 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx @@ -1,5 +1,5 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { action, computed, makeObservable, observable, ObservableMap, observe } from 'mobx'; +import { action, computed, makeObservable, observable, ObservableMap, observe, trace } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { Doc, DocListCast, Field, NumListCast, Opt, StrListCast } from '../../../../fields/Doc'; @@ -25,6 +25,8 @@ import { CollectionSubView } from '../CollectionSubView'; import './CollectionSchemaView.scss'; import { SchemaColumnHeader } from './SchemaColumnHeader'; import { SchemaRowBox } from './SchemaRowBox'; +import { Popup, PopupTrigger, Type } from 'browndash-components'; +import { SettingsManager } from '../../../util/SettingsManager'; const { default: { SCHEMA_NEW_NODE_HEIGHT } } = require('../../global/globalCssVariables.module.scss'); // prettier-ignore export enum ColumnType { @@ -161,7 +163,7 @@ export class CollectionSchemaView extends CollectionSubView() { (change as any).added.forEach((doc: Doc) => // for each document added Doc.GetAllPrototypes(doc.value as Doc).forEach(proto => // for all of its prototypes (and itself) Object.keys(proto).forEach(action(key => // check if any of its keys are new, and add them - !this.fieldInfos.get(key) && this.fieldInfos.set(key, new FInfo(key, key === 'author')))))); + !this.fieldInfos.get(key) && this.fieldInfos.set(key, new FInfo("-no description-", key === 'author')))))); break; case 'update': //let oldValue = change.oldValue; // fill this in if the entire child list will ever be reassigned with a new list } @@ -681,6 +683,7 @@ export class CollectionSchemaView extends CollectionSubView() { } else { this.setKey(this._menuValue, this._newFieldDefault); } + this._columnMenuIndex = undefined; })}> done
@@ -688,12 +691,12 @@ export class CollectionSchemaView extends CollectionSubView() { ); } - onPassiveWheel = (e: WheelEvent) => { + onKeysPassiveWheel = (e: WheelEvent) => { // if scrollTop is 0, then don't let wheel trigger scroll on any container (which it would since onScroll won't be triggered on this) - if (!this._oldWheel.scrollTop && e.deltaY <= 0) e.preventDefault(); + if (!this._oldKeysWheel.scrollTop && e.deltaY <= 0) e.preventDefault(); e.stopPropagation(); }; - _oldWheel: any; + _oldKeysWheel: any; @computed get keysDropdown() { return (
@@ -708,9 +711,9 @@ export class CollectionSchemaView extends CollectionSubView() {
{ - this._oldWheel?.removeEventListener('wheel', this.onPassiveWheel); - this._oldWheel = r; - r?.addEventListener('wheel', this.onPassiveWheel, { passive: false }); + this._oldKeysWheel?.removeEventListener('wheel', this.onKeysPassiveWheel); + this._oldKeysWheel = r; + r?.addEventListener('wheel', this.onKeysPassiveWheel, { passive: false }); }}> {this._menuKeys.map(key => (

- {key} - {this.fieldInfos.get(key)!.fieldType ? ', ' : ''} + {key} + {this.fieldInfos.get(key)!.fieldType ? ':' : ''} {this.fieldInfos.get(key)!.fieldType} +   {this.fieldInfos.get(key)!.description}

-

{this.fieldInfos.get(key)!.description}

))}
@@ -740,16 +743,17 @@ export class CollectionSchemaView extends CollectionSubView() { const x = this._columnMenuIndex! == -1 ? 0 : this.displayColumnWidths.reduce((total, curr, index) => total + (index < this._columnMenuIndex! ? curr : 0), CollectionSchemaView._rowMenuWidth); return (
- e.stopPropagation()} /> + e.stopPropagation()} /> + {this._makeNewField ? this.newFieldMenu : this.keysDropdown} +
+ ); + } + get renderKeysMenu() { + console.log('RNDERMENUT:' + this._columnMenuIndex); + return ( +
+ e.stopPropagation()} /> {this._makeNewField ? this.newFieldMenu : this.keysDropdown} -
{ - e.stopPropagation(); - this.closeColumnMenu(); - })}> - cancel -
); } @@ -833,6 +837,8 @@ export class CollectionSchemaView extends CollectionSubView() { isContentActive = () => this._props.isSelected() || this._props.isContentActive(); screenToLocal = () => this.ScreenToLocalBoxXf().translate(-this.tableWidth, 0); previewWidthFunc = () => this.previewWidth; + onPassiveWheel = (e: WheelEvent) => e.stopPropagation(); + _oldWheel: any; render() { return (
this.createDashEventsTarget(ele)} onDrop={this.onExternalDrop.bind(this)}> @@ -841,15 +847,23 @@ export class CollectionSchemaView extends CollectionSubView() { className="schema-table" style={{ width: `calc(100% - ${this.previewWidth}px)` }} onWheel={e => this._props.isContentActive() && e.stopPropagation()} - ref={r => { - // prevent wheel events from passively propagating up through containers - r?.addEventListener('wheel', (e: WheelEvent) => {}, { passive: false }); + ref={ele => { + // prevent wheel events from passively propagating up through containers and prevents containers from preventDefault which would block scrolling + this._oldWheel?.removeEventListener('wheel', this.onPassiveWheel); + (this._oldWheel = ele)?.addEventListener('wheel', this.onPassiveWheel, { passive: false }); }}>
-
(this._columnMenuIndex === -1 ? this.closeColumnMenu() : this.openColumnMenu(-1, true))}> - -
+ this.openColumnMenu(-1, true)} icon="plus" />} + trigger={PopupTrigger.CLICK} + type={Type.TERT} + isOpen={this._columnMenuIndex !== -1 ? false : undefined} + popup={this.renderKeysMenu} + />
{this.columnKeys.map((key, index) => ( ))}
- {this._columnMenuIndex !== undefined && this.renderColumnMenu} + {this._columnMenuIndex !== undefined && this._columnMenuIndex !== -1 && this.renderColumnMenu} {this._filterColumnIndex !== undefined && this.renderFilterMenu} (this._tableContentRef = ref)} /> {this.layoutDoc.chromeHidden ? null : ( diff --git a/src/client/views/nodes/LinkAnchorBox.tsx b/src/client/views/nodes/LinkAnchorBox.tsx index 00e1f04c5..0a4325d8c 100644 --- a/src/client/views/nodes/LinkAnchorBox.tsx +++ b/src/client/views/nodes/LinkAnchorBox.tsx @@ -5,7 +5,7 @@ import { Utils, emptyFunction, setupMoveUpEvents } from '../../../Utils'; import { Doc } from '../../../fields/Doc'; import { NumCast, StrCast } from '../../../fields/Types'; import { TraceMobx } from '../../../fields/util'; -import { DragManager } from '../../util/DragManager'; +import { DragManager, dropActionType } from '../../util/DragManager'; import { LinkFollower } from '../../util/LinkFollower'; import { SelectionManager } from '../../util/SelectionManager'; import { ViewBoxBaseComponent } from '../DocComponent'; @@ -54,7 +54,7 @@ export class LinkAnchorBox extends ViewBoxBaseComponent() { const separation = Math.sqrt((pt[0] - e.clientX) * (pt[0] - e.clientX) + (pt[1] - e.clientY) * (pt[1] - e.clientY)); if (separation > 100) { const dragData = new DragManager.DocumentDragData([this.Document]); - dragData.dropAction = 'embed'; + dragData.dropAction = dropActionType.embed; dragData.dropPropertiesToRemove = ['link_anchor_1_x', 'link_anchor_1_y', 'link_anchor_2_x', 'link_anchor_2_y', 'onClick']; DragManager.StartDocumentDrag([this._ref.current!], dragData, pt[0], pt[1]); return true; diff --git a/src/client/views/nodes/RecordingBox/RecordingBox.tsx b/src/client/views/nodes/RecordingBox/RecordingBox.tsx index f6d94ce05..e38a42b29 100644 --- a/src/client/views/nodes/RecordingBox/RecordingBox.tsx +++ b/src/client/views/nodes/RecordingBox/RecordingBox.tsx @@ -11,7 +11,7 @@ import { Upload } from '../../../../server/SharedMediaTypes'; import { DocumentType } from '../../../documents/DocumentTypes'; import { Docs } from '../../../documents/Documents'; import { DocumentManager } from '../../../util/DocumentManager'; -import { DragManager } from '../../../util/DragManager'; +import { DragManager, dropActionType } from '../../../util/DragManager'; import { ScriptingGlobals } from '../../../util/ScriptingGlobals'; import { Presentation } from '../../../util/TrackMovements'; import { undoBatch } from '../../../util/UndoManager'; @@ -251,7 +251,7 @@ ScriptingGlobals.add(function resumeWorkspaceReplaying(value: Doc, _readOnly_: b ScriptingGlobals.add(function startRecordingDrag(value: { doc: Doc | string; e: React.PointerEvent }) { if (DocCast(value.doc)) { - DragManager.StartDocumentDrag([value.e.target as HTMLElement], new DragManager.DocumentDragData([DocCast(value.doc)], 'embed'), value.e.clientX, value.e.clientY); + DragManager.StartDocumentDrag([value.e.target as HTMLElement], new DragManager.DocumentDragData([DocCast(value.doc)], dropActionType.embed), value.e.clientX, value.e.clientY); value.e.preventDefault(); return true; } diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 2d5239f06..4a1a51558 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -30,7 +30,7 @@ import { Docs, DocUtils } from '../../../documents/Documents'; import { CollectionViewType } from '../../../documents/DocumentTypes'; import { DictationManager } from '../../../util/DictationManager'; import { DocumentManager } from '../../../util/DocumentManager'; -import { DragManager } from '../../../util/DragManager'; +import { DragManager, dropActionType } from '../../../util/DragManager'; import { MakeTemplate } from '../../../util/DropConverter'; import { LinkManager } from '../../../util/LinkManager'; import { RTFMarkup } from '../../../util/RTFMarkup'; @@ -624,7 +624,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent Date: Fri, 8 Mar 2024 16:17:02 -0500 Subject: cleaned up MakeTemplate api and currentUserUtils templates for clicks etc. --- src/client/documents/Documents.ts | 9 ++++ src/client/util/CurrentUserUtils.ts | 35 ++++++++-------- src/client/util/DropConverter.ts | 48 ++++++++++++++-------- src/client/views/collections/TreeView.tsx | 2 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 4 +- 5 files changed, 60 insertions(+), 38 deletions(-) (limited to 'src/client/views/nodes/formattedText/FormattedTextBox.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index b7d8222b9..e6969d1f3 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -1024,6 +1024,15 @@ export namespace Docs { return InstanceFromProto(Prototypes.get(DocumentType.PRES), new List(), options); } + /** + * Creates a Doc to edit a script and write the compiled script into the specified field. + * Typically, this would be used to create a template that can then be applied to some other Doc + * in order to customize a behavior, such as onClick. + * @param script + * @param options + * @param fieldKey the field that the compiled script is written into. + * @returns the Scripting Doc + */ export function ScriptingDocument(script: Opt | null, options: DocumentOptions = {}, fieldKey?: string) { return InstanceFromProto(Prototypes.get(DocumentType.SCRIPTING), script ? script : undefined, { ...options, layout: fieldKey ? ScriptingBox.LayoutString(fieldKey) : undefined }); } diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index cfba003fc..564a46514 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -105,9 +105,12 @@ export class CurrentUserUtils { { opts: { title: "onCheckedClick"}, script: "console.log(heading, checked, containingTreeView)"}, ]; const reqdClickList = reqdTempOpts.map(opts => { + const title = opts.opts.title?.toString(); const allOpts = {...reqdClickOpts, ...opts.opts}; - const clickDoc = tempClicks ? DocListCast(tempClicks.data).find(doc => doc.title === opts.opts.title): undefined; - return DocUtils.AssignOpts(clickDoc, allOpts) ?? MakeTemplate(Docs.Create.ScriptingDocument(ScriptField.MakeScript(opts.script, {heading:Doc.name, checked:"boolean", containingTreeView:Doc.name}), allOpts), true, opts.opts.title?.toString()); + const clickDoc = tempClicks ? DocListCast(tempClicks.data).find(doc => doc.title === title): undefined; + const script = ScriptField.MakeScript(opts.script, {heading:Doc.name, checked:"boolean", containingTreeView:Doc.name}); + const scriptDoc = Docs.Create.ScriptingDocument(script, allOpts, title) + return DocUtils.AssignOpts(clickDoc, allOpts) ?? MakeTemplate(scriptDoc); }); const reqdOpts:DocumentOptions = {title: "click editor templates", _height:75, isSystem: true}; @@ -118,13 +121,13 @@ export class CurrentUserUtils { static setupNoteTemplates(doc: Doc, field="template_notes") { const tempNotes = DocCast(doc[field]); const reqdTempOpts:DocumentOptions[] = [ - { noteType: "Postit", backgroundColor: "yellow", icon: "sticky-note"}, - { noteType: "Idea", backgroundColor: "pink", icon: "lightbulb" }, - { noteType: "Topic", backgroundColor: "lightblue", icon: "book-open" }]; + { title: "Postit", backgroundColor: "yellow", icon: "sticky-note"}, + { title: "Idea", backgroundColor: "pink", icon: "lightbulb" }, + { title: "Topic", backgroundColor: "lightblue", icon: "book-open" }]; const reqdNoteList = reqdTempOpts.map(opts => { - const reqdOpts = {...opts, isSystem:true, title: "text", width:200, layout_autoHeight: true, layout_fitWidth: true}; - const noteType = tempNotes ? DocListCast(tempNotes.data).find(doc => doc.noteType === opts.noteType): undefined; - return DocUtils.AssignOpts(noteType, reqdOpts) ?? MakeTemplate(Docs.Create.TextDocument("",reqdOpts), true, opts.noteType??"Note"); + const reqdOpts = {...opts, isSystem:true, width:200, layout_autoHeight: true, layout_fitWidth: true}; + const noteTemp = tempNotes ? DocListCast(tempNotes.data).find(doc => doc.title === opts.title): undefined; + return DocUtils.AssignOpts(noteTemp, reqdOpts) ?? MakeTemplate(Docs.Create.TextDocument("",reqdOpts)); }); const reqdOpts:DocumentOptions = { title: "Note Layouts", _height: 75, isSystem: true }; @@ -149,16 +152,16 @@ export class CurrentUserUtils { const templateIconsDoc = DocUtils.AssignOpts(DocCast(doc[field]), reqdOpts) ?? (doc[field] = Docs.Create.TreeDocument([], reqdOpts)); const makeIconTemplate = (type: DocumentType | undefined, templateField: string, opts:DocumentOptions) => { - const iconFieldName = "icon" + (type ? "_" + type : ""); - const curIcon = DocCast(templateIconsDoc[iconFieldName]); + const title = "icon" + (type ? "_" + type : ""); + const curIcon = DocCast(templateIconsDoc[title]); let creator = labelBox; switch (opts.iconTemplate) { case DocumentType.IMG : creator = imageBox; break; case DocumentType.FONTICON: creator = fontBox; break; } - const allopts = {isSystem: true, onClickScriptDisable: "never", ...opts}; + const allopts = {isSystem: true, onClickScriptDisable: "never", ...opts, title}; return DocUtils.AssignScripts( (curIcon?.iconTemplate === opts.iconTemplate ? - DocUtils.AssignOpts(curIcon, allopts):undefined) ?? ((templateIconsDoc[iconFieldName] = MakeTemplate(creator(allopts, templateField), true, iconFieldName, templateField))), + DocUtils.AssignOpts(curIcon, allopts):undefined) ?? ((templateIconsDoc[title] = MakeTemplate(creator(allopts, templateField)))), {onClick:"deiconifyView(documentView)", onDoubleClick: "deiconifyViewToLightbox(documentView)", }); }; const labelBox = (opts: DocumentOptions, fieldKey:string) => Docs.Create.LabelDocument({ @@ -211,7 +214,7 @@ export class CurrentUserUtils { }; const headerBtnHgt = 10; const headerTemplate = (opts:DocumentOptions) => { - const header = Docs.Create.RTFDocument(new RichTextField(JSON.stringify(json), ""), { ...opts, title: "text", + const header = Docs.Create.RTFDocument(new RichTextField(JSON.stringify(json), ""), { ...opts, title: "Untitled Header", layout: "" + ` ` + @@ -224,7 +227,7 @@ export class CurrentUserUtils { // " " + // " " + // "
"; - MakeTemplate(Doc.GetProto(header), true, "Untitled Header"); + MakeTemplate(Doc.GetProto(header)); return header; } const slideView = (opts:DocumentOptions) => { @@ -232,9 +235,9 @@ export class CurrentUserUtils { [ Docs.Create.MulticolumnDocument([], { title: "hero", _height: 200, isSystem: true }), Docs.Create.TextDocument("", { title: "text", _layout_fitWidth:true, _height: 100, isSystem: true, _text_fontFamily: StrCast(Doc.UserDoc().fontFamily), _text_fontSize: StrCast(Doc.UserDoc().fontSize) }) - ], opts); + ], {...opts, title: "Untitled Slide View"}); - MakeTemplate(Doc.GetProto(slide), true, "Untitled Slide View"); + MakeTemplate(Doc.GetProto(slide)); return slide; } const plotlyApi = () => { diff --git a/src/client/util/DropConverter.ts b/src/client/util/DropConverter.ts index ba981145d..3df3e36c6 100644 --- a/src/client/util/DropConverter.ts +++ b/src/client/util/DropConverter.ts @@ -12,43 +12,55 @@ import { ButtonType, FontIconBox } from '../views/nodes/FontIconBox/FontIconBox' import { DragManager } from './DragManager'; import { ScriptingGlobals } from './ScriptingGlobals'; -export function MakeTemplate(doc: Doc, first: boolean = true, rename: Opt = undefined, templateField: string = '') { - if (templateField) doc[DocData].title = templateField; /// the title determines which field is being templated - doc.isTemplateDoc = makeTemplate(doc, first, rename); +/** + * Converts a Doc to a render template that can be applied to other Docs to customize how they render while + * still using the other Doc as the backing data store (ie, dataDoc). During rendering, if a layout Doc is provided + * with 'isTemplateDoc' set, then the layout Doc is treated as a template for the rendered Doc. The template Doc is + * "expanded" to create an template instance for the rendered Doc. + * + * + * @param doc the doc to convert to a template + * @returns 'doc' + */ +export function MakeTemplate(doc: Doc) { + doc.isTemplateDoc = makeTemplate(doc, true); return doc; } -// -// converts 'doc' into a template that can be used to render other documents. -// the title of doc is used to determine which field is being templated, so -// passing a value for 'rename' allows the doc to be given a meangingful name -// after it has been converted to -function makeTemplate(doc: Doc, first: boolean = true, rename: Opt = undefined): boolean { + +/** + * Recursively converts 'doc' into a template that can be used to render other documents. + * + * For recurive Docs in the template, their target fieldKey is defined by their title, + * not by whatever fieldKey they used in their layout. + * @param doc + * @param first whether this is the topmost root of the recursive template + * @returns whether a template was successfully created + */ +function makeTemplate(doc: Doc, first: boolean = true): boolean { const layoutDoc = doc.layout instanceof Doc && doc.layout.isTemplateForField ? doc.layout : doc; if (layoutDoc.layout instanceof Doc) { - // its already a template - return true; + return true; // its already a template } const layout = StrCast(layoutDoc.layout).match(/fieldKey={'[^']*'}/)![0]; const fieldKey = layout.replace("fieldKey={'", '').replace(/'}$/, ''); const docs = DocListCast(layoutDoc[fieldKey]); - let any = false; + let isTemplate = false; docs.forEach(d => { if (!StrCast(d.title).startsWith('-')) { - any = Doc.MakeMetadataFieldTemplate(d, layoutDoc[DocData]) || any; + isTemplate = Doc.MakeMetadataFieldTemplate(d, layoutDoc[DocData]) || isTemplate; } else if (d.type === DocumentType.COL || d.data instanceof RichTextField) { - any = makeTemplate(d, false) || any; + isTemplate = makeTemplate(d, false) || isTemplate; } }); if (first && !docs.length) { // bcz: feels hacky : if the root level document has items, it's not a field template - any = Doc.MakeMetadataFieldTemplate(doc, layoutDoc[DocData], true) || any; + isTemplate = Doc.MakeMetadataFieldTemplate(doc, layoutDoc[DocData], true) || isTemplate; } else if (layoutDoc[fieldKey] instanceof RichTextField || layoutDoc[fieldKey] instanceof ImageField) { if (!StrCast(layoutDoc.title).startsWith('-')) { - any = Doc.MakeMetadataFieldTemplate(layoutDoc, layoutDoc[DocData], true); + isTemplate = Doc.MakeMetadataFieldTemplate(layoutDoc, layoutDoc[DocData], true); } } - rename && (doc.title = rename); - return any; + return isTemplate; } export function convertDropDataToButtons(data: DragManager.DocumentDragData) { data?.draggedDocuments.map((doc, i) => { diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index 285a789e6..0c0e49411 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -631,7 +631,7 @@ export class TreeView extends ObservableReactComponent { } return (
- {!docs?.length || this._props.AddToMap /* hack to identify pres box trees */ ? null : ( + {!docs?.length || this.treeView.outlineMode || this._props.AddToMap /* hack to identify pres box trees */ ? null : (
{ if (!this.layoutDoc.isTemplateDoc) { - const title = StrCast(this.Document.title); - this.Document.title = 'text'; - MakeTemplate(this.Document, true, title); + MakeTemplate(this.Document); } Doc.UserDoc().defaultTextLayout = new PrefetchProxy(this.Document); Doc.AddDocToList(Cast(Doc.UserDoc().template_notes, Doc, null), 'data', this.Document); -- cgit v1.2.3-70-g09d2 From f1ed1cff137c06afc4d4db8a8778f7827404889b Mon Sep 17 00:00:00 2001 From: bobzel Date: Sat, 9 Mar 2024 19:05:30 -0500 Subject: fixed up default text that uses a template to process an initial carriage return properly. fixed text with inherited templates to be able to show fields with a default dashField value from template that can be overidden on instance. --- src/client/documents/Documents.ts | 11 +++--- src/client/views/MarqueeAnnotator.tsx | 4 +-- src/client/views/PreviewCursor.tsx | 2 +- src/client/views/collections/TreeView.tsx | 2 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 36 +++++++++++-------- .../collections/collectionFreeForm/MarqueeView.tsx | 2 +- .../collectionSchema/SchemaTableCell.tsx | 2 +- src/client/views/nodes/MapBox/MapBox.tsx | 4 +-- .../views/nodes/MapboxMapBox/MapboxContainer.tsx | 4 +-- .../views/nodes/formattedText/FormattedTextBox.tsx | 40 ++++++++++------------ 10 files changed, 55 insertions(+), 52 deletions(-) (limited to 'src/client/views/nodes/formattedText/FormattedTextBox.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index e6969d1f3..7a3b965fe 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -3,7 +3,7 @@ import { action, reaction, runInAction } from 'mobx'; import { basename } from 'path'; import { DateField } from '../../fields/DateField'; import { Doc, DocListCast, Field, LinkedTo, Opt, StrListCast, updateCachedAcls } from '../../fields/Doc'; -import { Initializing } from '../../fields/DocSymbols'; +import { DocData, Initializing } from '../../fields/DocSymbols'; import { Id } from '../../fields/FieldSymbols'; import { HtmlField } from '../../fields/HtmlField'; import { InkField, PointData } from '../../fields/InkField'; @@ -1981,10 +1981,8 @@ export namespace DocUtils { } } - export function GetNewTextDoc(title: string, x: number, y: number, width?: number, height?: number, noMargins?: boolean, annotationOn?: Doc, backgroundColor?: string) { + export function GetNewTextDoc(title: string, x: number, y: number, width?: number, height?: number, annotationOn?: Doc, backgroundColor?: string) { const tbox = Docs.Create.TextDocument('', { - _xMargin: noMargins ? 0 : undefined, - _yMargin: noMargins ? 0 : undefined, annotationOn, backgroundColor, _width: width || 200, @@ -1997,11 +1995,14 @@ export namespace DocUtils { _layout_enableAltContentUI: BoolCast(Doc.UserDoc().defaultToFlashcards), title, }); + const template = Doc.UserDoc().defaultTextLayout; if (template instanceof Doc) { + // if a default text template is specified tbox._width = NumCast(template._width); tbox.layout_fieldKey = 'layout_' + StrCast(template.title); - Doc.GetProto(tbox)[StrCast(tbox.layout_fieldKey)] = template; + Doc.GetProto(tbox)[StrCast(tbox.layout_fieldKey)] = template; // set the text doc's layout to render with the text template + tbox[DocData].proto = template; // and also set the text doc to inherit from the template (this allows the template to specify default field values) } return tbox; } diff --git a/src/client/views/MarqueeAnnotator.tsx b/src/client/views/MarqueeAnnotator.tsx index a4303c3aa..f59042b04 100644 --- a/src/client/views/MarqueeAnnotator.tsx +++ b/src/client/views/MarqueeAnnotator.tsx @@ -88,7 +88,7 @@ export class MarqueeAnnotator extends ObservableReactComponent this.highlight(this.props.highlightDragSrcColor ?? 'rgba(173, 216, 230, 0.75)', true, undefined, true); // hyperlink color const targetCreator = (annotationOn: Doc | undefined) => { - const target = DocUtils.GetNewTextDoc('Note linked to ' + this.props.Document.title, 0, 0, 100, 100, undefined, annotationOn, 'yellow'); + const target = DocUtils.GetNewTextDoc('Note linked to ' + this.props.Document.title, 0, 0, 100, 100, annotationOn, 'yellow'); FormattedTextBox.SetSelectOnLoad(target); return target; }; diff --git a/src/client/views/PreviewCursor.tsx b/src/client/views/PreviewCursor.tsx index 456b753b4..a94c18295 100644 --- a/src/client/views/PreviewCursor.tsx +++ b/src/client/views/PreviewCursor.tsx @@ -85,7 +85,7 @@ export class PreviewCursor extends ObservableReactComponent<{}> { } else { FormattedTextBox.PasteOnLoad = e; if (e.clipboardData.getData('dash/pdfAnchor')) e.preventDefault(); - UndoManager.RunInBatch(() => this._addLiveTextDoc?.(DocUtils.GetNewTextDoc('', newPoint[0], newPoint[1], 500, undefined, undefined, undefined)), 'paste'); + UndoManager.RunInBatch(() => this._addLiveTextDoc?.(DocUtils.GetNewTextDoc('', newPoint[0], newPoint[1], 500, undefined, undefined)), 'paste'); } } //pasting in images diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index 0c0e49411..c6bbcb0a5 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -884,7 +884,7 @@ export class TreeView extends ObservableReactComponent { // prettier-ignore switch (property.split(':')[0]) { case StyleProp.Opacity: return this.treeView.outlineMode ? undefined : 1; - case StyleProp.BackgroundColor: return this.selected ? '#7089bb' : StrCast(doc._backgroundColor, StrCast(doc.backgroundColor)); + case StyleProp.BackgroundColor: return this.selected ? '#7089bb' : undefined;//StrCast(doc._backgroundColor, StrCast(doc.backgroundColor)); case StyleProp.Highlighting: if (this.treeView.outlineMode) return undefined; case StyleProp.BoxShadow: return undefined; case StyleProp.DocContents: diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 4eb946939..9500b918a 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -30,7 +30,7 @@ import { SelectionManager } from '../../../util/SelectionManager'; import { freeformScrollMode } from '../../../util/SettingsManager'; import { SnappingManager } from '../../../util/SnappingManager'; import { Transform } from '../../../util/Transform'; -import { undoBatch, UndoManager } from '../../../util/UndoManager'; +import { undoable, undoBatch, UndoManager } from '../../../util/UndoManager'; import { Timeline } from '../../animationtimeline/Timeline'; import { ContextMenu } from '../../ContextMenu'; import { GestureOverlay } from '../../GestureOverlay'; @@ -1146,23 +1146,29 @@ export class CollectionFreeFormView extends CollectionSubView this._props.isContentActive(); - @undoBatch + /** + * Create a new text note of the same style as the one being typed into. + * If the text doc is be part of a larger templated doc, the new Doc will be a copy of the templated Doc + * + * @param fieldProps render props for the text doc being typed into + * @param below whether to place the new text Doc below or to the right of the one being typed into. + * @returns whether the new text doc was created and added successfully + */ + createTextDocCopy = undoable((fieldProps: FieldViewProps, below: boolean) => { + const textDoc = DocCast(fieldProps.Document.rootDocument, fieldProps.Document); + const newDoc = Doc.MakeCopy(textDoc, true); + newDoc[DocData][Doc.LayoutFieldKey(newDoc, fieldProps.LayoutTemplateString)] = undefined; // the copy should not copy the text contents of it source, just the render style + newDoc.x = NumCast(textDoc.x) + (below ? 0 : NumCast(textDoc._width) + 10); + newDoc.y = NumCast(textDoc.y) + (below ? NumCast(textDoc._height) + 10 : 0); + FormattedTextBox.SetSelectOnLoad(newDoc); + FormattedTextBox.DontSelectInitialText = true; + return this.addDocument?.(newDoc); + }, 'copied text note'); + onKeyDown = (e: React.KeyboardEvent, fieldProps: FieldViewProps) => { if ((e.metaKey || e.ctrlKey || e.altKey || fieldProps.Document._createDocOnCR) && ['Tab', 'Enter'].includes(e.key)) { e.stopPropagation?.(); - const below = !e.altKey && e.key !== 'Tab'; - const layout_fieldKey = StrCast(fieldProps.fieldKey); - const newDoc = Doc.MakeCopy(fieldProps.Document, true); - const dataField = fieldProps.Document[Doc.LayoutFieldKey(newDoc)]; - newDoc[DocData][Doc.LayoutFieldKey(newDoc)] = dataField === undefined || Cast(dataField, listSpec(Doc), null)?.length !== undefined ? new List([]) : undefined; - if (below) newDoc.y = NumCast(fieldProps.Document.y) + NumCast(fieldProps.Document._height) + 10; - else newDoc.x = NumCast(fieldProps.Document.x) + NumCast(fieldProps.Document._width) + 10; - if (layout_fieldKey !== 'layout' && fieldProps.Document[layout_fieldKey] instanceof Doc) { - newDoc[layout_fieldKey] = fieldProps.Document[layout_fieldKey]; - } - newDoc[DocData].text = undefined; - FormattedTextBox.SetSelectOnLoad(newDoc); - return this.addDocument?.(newDoc); + return this.createTextDocCopy(fieldProps, !e.altKey && e.key !== 'Tab'); } }; @computed get childPointerEvents() { diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index e22b83307..b913e05ad 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -178,7 +178,7 @@ export class MarqueeView extends ObservableReactComponent() implem }); const targetCreator = (annotationOn: Doc | undefined) => { - const target = DocUtils.GetNewTextDoc('Note linked to ' + this.Document.title, 0, 0, 100, 100, undefined, annotationOn, 'yellow'); + const target = DocUtils.GetNewTextDoc('Note linked to ' + this.Document.title, 0, 0, 100, 100, annotationOn, 'yellow'); FormattedTextBox.SetSelectOnLoad(target); return target; }; @@ -592,7 +592,7 @@ export class MapBox extends ViewBoxAnnotatableComponent() implem /// this should use SELECTED pushpin for lat/long if there is a selection, otherwise CENTER const anchor = Docs.Create.ConfigDocument({ title: 'MapAnchor:' + this.Document.title, - text: StrCast(this.selectedPinOrRoute?.map) || StrCast(this.Document.map) || 'map location', + text: (StrCast(this.selectedPinOrRoute?.map) || StrCast(this.Document.map) || 'map location') as any, config_latitude: NumCast((existingPin ?? this.selectedPinOrRoute)?.latitude ?? this.dataDoc.latitude), config_longitude: NumCast((existingPin ?? this.selectedPinOrRoute)?.longitude ?? this.dataDoc.longitude), config_map_zoom: NumCast(this.dataDoc.map_zoom), diff --git a/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx b/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx index 8a5bd7ce6..3eb051dbf 100644 --- a/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx +++ b/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx @@ -232,7 +232,7 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent }); const targetCreator = (annotationOn: Doc | undefined) => { - const target = DocUtils.GetNewTextDoc('Note linked to ' + this.Document.title, 0, 0, 100, 100, undefined, annotationOn, 'yellow'); + const target = DocUtils.GetNewTextDoc('Note linked to ' + this.Document.title, 0, 0, 100, 100, annotationOn, 'yellow'); FormattedTextBox.SetSelectOnLoad(target); return target; }; @@ -466,7 +466,7 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent /// this should use SELECTED pushpin for lat/long if there is a selection, otherwise CENTER const anchor = Docs.Create.ConfigDocument({ title: 'MapAnchor:' + this.Document.title, - text: StrCast(this.selectedPin?.map) || StrCast(this.Document.map) || 'map location', + text: (StrCast(this.selectedPin?.map) || StrCast(this.Document.map) || 'map location') as any, config_latitude: NumCast((existingPin ?? this.selectedPin)?.latitude ?? this.dataDoc.latitude), config_longitude: NumCast((existingPin ?? this.selectedPin)?.longitude ?? this.dataDoc.longitude), config_map_zoom: NumCast(this.dataDoc.map_zoom), diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 54e3e7b44..1ff7274f8 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -67,7 +67,6 @@ import { RichTextMenu, RichTextMenuPlugin } from './RichTextMenu'; import { RichTextRules } from './RichTextRules'; import { schema } from './schema_rts'; import { SummaryView } from './SummaryView'; -import Select from 'react-select'; // import * as applyDevTools from 'prosemirror-dev-tools'; @observer export class FormattedTextBox extends ViewBoxAnnotatableComponent() implements ViewBoxInterface { @@ -100,7 +99,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent; private _keymap: any = undefined; @@ -306,7 +304,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { - const target = DocUtils.GetNewTextDoc('Note linked to ' + this.Document.title, 0, 0, 100, 100, undefined, annotationOn); + const target = DocUtils.GetNewTextDoc('Note linked to ' + this.Document.title, 0, 0, 100, 100, annotationOn); FormattedTextBox.SetSelectOnLoad(target); return target; }; @@ -1457,39 +1455,37 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent m.type !== mark.type), mark]; - const tr = this._editorView.state.tr - .setStoredMarks(storedMarks) - .insertText(FormattedTextBox.SelectOnLoadChar, this._editorView.state.doc.content.size - 1, this._editorView.state.doc.content.size) - .setStoredMarks(storedMarks); + const tr1 = this._editorView.state.tr.setStoredMarks(storedMarks); + const tr2 = selLoadChar === 'Enter' ? tr1.insert(this._editorView.state.doc.content.size - 1, schema.nodes.paragraph.create()) : tr1.insertText(selLoadChar, this._editorView.state.doc.content.size - 1); + const tr = tr2.setStoredMarks(storedMarks); + this._editorView.dispatch(tr.setSelection(new TextSelection(tr.doc.resolve(tr.doc.content.size)))); } else if (curText && !FormattedTextBox.DontSelectInitialText) { selectAll(this._editorView.state, this._editorView?.dispatch); } } - selectOnLoad && this._editorView!.focus(); + if (selectOnLoad) { + FormattedTextBox.DontSelectInitialText = false; + this._editorView!.focus(); + } if (this._props.isContentActive()) this.prepareForTyping(); - if (this._editorView) { - const tr = this._editorView.state.tr; - const { from, to } = tr.selection; - // for some reason, the selection is sometimes lost in the sidebar view when prosemirror syncs the seledtion with the dom, so reset the selection after the document has ben fully instantiated. - if (FormattedTextBox.DontSelectInitialText) setTimeout(() => this._editorView?.dispatch(tr.setSelection(new TextSelection(tr.doc.resolve(from), tr.doc.resolve(to)))), 250); - - if (FormattedTextBox.PasteOnLoad) { - const pdfAnchorId = FormattedTextBox.PasteOnLoad.clipboardData?.getData('dash/pdfAnchor'); - FormattedTextBox.PasteOnLoad = undefined; - pdfAnchorId && this.addPdfReference(pdfAnchorId); - } + if (this._editorView && FormattedTextBox.PasteOnLoad) { + const pdfAnchorId = FormattedTextBox.PasteOnLoad.clipboardData?.getData('dash/pdfAnchor'); + FormattedTextBox.PasteOnLoad = undefined; + pdfAnchorId && this.addPdfReference(pdfAnchorId); } - FormattedTextBox.DontSelectInitialText = false; } // 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. -- cgit v1.2.3-70-g09d2