From 923b0d20cd95311122ec5886698b3fb2dfadb882 Mon Sep 17 00:00:00 2001 From: srichman333 Date: Fri, 12 Jan 2024 12:56:09 -0500 Subject: live schema toggle works on refresh --- .../views/collections/collectionSchema/CollectionSchemaView.scss | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src/client/views/collections/collectionSchema/CollectionSchemaView.scss') diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss index 02131ae22..da9da8fbe 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss +++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss @@ -18,17 +18,21 @@ .schema-add { position: relative; - height: 30; + height: 35; display: flex; align-items: center; + top: -10px; width: 100%; text-align: right; background: lightgray; .editableView-container-editing { width: 100%; + height: 35px; + margin: 20px; } .editableView-input { width: 100%; + margin: 20px; float: right; text-align: right; background: yellow; -- cgit v1.2.3-70-g09d2 From 001127c07f95173d7036db19d07dcfb1135f3caa Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 22 Jan 2024 21:45:28 -0500 Subject: fixed schema rows to render, fix for resizing docs from left side. all locking docs in non freeform view. fix for labelBox with multiple rows to keep top rows. cleaned up docViewPath/containerViewPath & --- src/client/util/CurrentUserUtils.ts | 2 +- src/client/views/DocComponent.tsx | 20 +------- src/client/views/DocumentDecorations.tsx | 9 ++-- src/client/views/MainView.tsx | 7 +-- src/client/views/MarqueeAnnotator.tsx | 6 +-- src/client/views/StyleProvider.tsx | 56 +++++++--------------- .../views/collections/CollectionNoteTakingView.tsx | 7 ++- .../views/collections/CollectionStackingView.tsx | 15 +++--- src/client/views/collections/CollectionSubView.tsx | 4 ++ src/client/views/collections/TabDocView.tsx | 4 +- src/client/views/collections/TreeView.tsx | 4 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 17 ++++--- .../collectionLinear/CollectionLinearView.tsx | 2 +- .../CollectionMulticolumnView.tsx | 2 +- .../CollectionMultirowView.tsx | 2 +- .../collectionSchema/CollectionSchemaView.scss | 3 +- .../collectionSchema/CollectionSchemaView.tsx | 2 +- .../collections/collectionSchema/SchemaRowBox.tsx | 18 ++++++- .../views/nodes/CollectionFreeFormDocumentView.tsx | 14 ++++-- src/client/views/nodes/ComparisonBox.tsx | 7 ++- src/client/views/nodes/DocumentContentsView.tsx | 12 ++--- src/client/views/nodes/DocumentView.tsx | 29 +++++------ src/client/views/nodes/LabelBox.scss | 5 +- src/client/views/nodes/LabelBox.tsx | 4 +- src/client/views/nodes/LinkAnchorBox.tsx | 11 +++-- src/client/views/nodes/LinkBox.tsx | 6 +-- src/client/views/nodes/PDFBox.tsx | 1 + .../views/nodes/formattedText/DashDocView.tsx | 7 ++- .../views/nodes/formattedText/DashFieldView.tsx | 2 +- src/client/views/nodes/trails/PresElementBox.tsx | 2 +- src/client/views/pdf/PDFViewer.tsx | 13 ++--- src/client/views/topbar/TopBar.tsx | 3 +- src/fields/Doc.ts | 5 ++ 33 files changed, 143 insertions(+), 158 deletions(-) (limited to 'src/client/views/collections/collectionSchema/CollectionSchemaView.scss') diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 7d9cb36c5..0b15e3add 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -192,7 +192,7 @@ export class CurrentUserUtils { {onClick:"deiconifyView(documentView)", onDoubleClick: "deiconifyViewToLightbox(documentView)", }); }; const labelBox = (opts: DocumentOptions, data?:string) => Docs.Create.LabelDocument({ - textTransform: "unset", letterSpacing: "unset", _singleLine: false, _label_minFontSize: 14, _label_maxFontSize: 24, layout_borderRounding: "5px", _width: 150, _height: 70, _xPadding: 10, _yPadding: 10, ...opts + textTransform: "unset", letterSpacing: "unset", _singleLine: false, _label_minFontSize: 14, _label_maxFontSize: 14, layout_borderRounding: "5px", _width: 150, _height: 70, _xPadding: 10, _yPadding: 10, ...opts }); const imageBox = (opts: DocumentOptions, url?:string) => Docs.Create.ImageDocument(url ?? "http://www.cs.brown.edu/~bcz/noImage.png", { "icon_nativeWidth": 360 / 4, "icon_nativeHeight": 270 / 4, iconTemplate:DocumentType.IMG, _width: 360 / 4, _height: 270 / 4, _layout_showTitle: "title", ...opts }); const fontBox = (opts:DocumentOptions, data?:string) => Docs.Create.FontIconDocument({ _nativeHeight: 30, _nativeWidth: 30, _width: 30, _height: 30, ...opts }); diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index 4400b3576..6aba4a042 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -1,6 +1,6 @@ import { action, computed, makeObservable, observable } from 'mobx'; import * as React from 'react'; -import { emptyPath, returnFalse } from '../../Utils'; +import { returnFalse } from '../../Utils'; import { DateField } from '../../fields/DateField'; import { Doc, DocListCast, Opt } from '../../fields/Doc'; import { AclAdmin, AclAugment, AclEdit, AclPrivate, AclReadonly, DocData } from '../../fields/DocSymbols'; @@ -41,7 +41,7 @@ export function DocComponent

() { } // This is the data part of a document -- ie, the data that is constant across all views of the document @computed get dataDoc() { - return this._props.Document[DocData] as Doc; + return this._props.Document[DocData]; } } return Component; @@ -55,16 +55,12 @@ export interface ViewBoxBaseProps { Document: Doc; TemplateDataDocument?: Doc; DocumentView?: () => DocumentView; - containerViewPath?: () => DocumentView[]; fieldKey: string; isSelected: () => boolean; isContentActive: () => boolean | undefined; ScreenToLocalTransform: () => Transform; renderDepth: number; } -function returnEmptyDocViewList() { - return [] as DocumentView[]; -} export function ViewBoxBaseComponent

() { class Component extends ObservableReactComponent> { ScreenToLocalBoxXf = () => this._props.ScreenToLocalTransform(); @@ -72,12 +68,6 @@ export function ViewBoxBaseComponent

() { get DocumentView() { return this._props.DocumentView; } - get docViewPath() { - return this.DocumentView?.().docViewPath ?? returnEmptyDocViewList; - } - get containerViewPath() { - return this._props.containerViewPath; - } //TODO This might be pretty inefficient if doc isn't observed, because computed doesn't cache then get Document() { return this._props.Document; @@ -132,12 +122,6 @@ export function ViewBoxAnnotatableComponent

() get DocumentView() { return this._props.DocumentView; } - get docViewPath() { - return this.DocumentView?.().docViewPath ?? returnEmptyDocViewList; - } - get containerViewPath() { - return this.DocumentView?.().containerViewPath ?? returnEmptyDocViewList; - } //TODO This might be pretty inefficient if doc isn't observed, because computed doesn't cache then @computed get Document() { return this._props.Document; diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index c96253405..8db972ef0 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -344,10 +344,7 @@ export class DocumentDecorations extends ObservableReactComponent UndoManager.RunInBatch( - () => SelectionManager.Docs.forEach(doc => - doc._pointerEvents = (doc._lockedPosition = !doc._lockedPosition)? 'none' : undefined ), - 'toggleBackground' ) // prettier-ignore + e => UndoManager.RunInBatch(() => SelectionManager.Docs.forEach(doc => Doc.toggleLockedPosition(doc)), 'toggleBackground') ); e.stopPropagation(); }; @@ -530,7 +527,7 @@ export class DocumentDecorations extends ObservableReactComponent 135 && seldocview.CollectionFreeFormDocumentView; + const useLock = bounds.r - bounds.x > 135; const useRotation = !hideResizers && seldocview.Document.type !== DocumentType.EQUATION && seldocview.CollectionFreeFormDocumentView; // when do we want an object to not rotate? const rotation = SelectionManager.Views.length == 1 ? seldocview.screenToContentsTransform().inverse().RotateDeg : 0; diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index cd6aeea41..d700ea020 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -56,13 +56,11 @@ import { CollectionLinearView } from './collections/collectionLinear'; import { LinkMenu } from './linking/LinkMenu'; import { AudioBox } from './nodes/AudioBox'; import { DocButtonState } from './nodes/DocumentLinksButton'; -import { DocumentView, DocumentViewInternal, OpenWhere, OpenWhereMod } from './nodes/DocumentView'; +import { DocumentView, DocumentViewInternal, OpenWhere, OpenWhereMod, returnEmptyDocViewList } from './nodes/DocumentView'; import { ImageBox } from './nodes/ImageBox'; import { LinkDescriptionPopup } from './nodes/LinkDescriptionPopup'; import { LinkDocPreview, LinkInfo } from './nodes/LinkDocPreview'; import { MapAnchorMenu } from './nodes/MapBox/MapAnchorMenu'; -import { MapBox } from './nodes/MapBox/MapBox'; -import { RadialMenu } from './nodes/RadialMenu'; import { TaskCompletionBox } from './nodes/TaskCompletedBox'; import { DashFieldViewMenu } from './nodes/formattedText/DashFieldView'; import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox'; @@ -898,6 +896,7 @@ export class MainView extends ObservableReactComponent<{}> {

{ isAnyChildContentActive={returnFalse} isContentActive={emptyFunction} isSelected={returnFalse} - containerViewPath={returnEmptyDoclist} moveDocument={this.moveButtonDoc} addDocument={this.addButtonDoc} addDocTab={DocumentViewInternal.addDocTabFunc} @@ -1021,7 +1019,6 @@ export class MainView extends ObservableReactComponent<{}> { - diff --git a/src/client/views/MarqueeAnnotator.tsx b/src/client/views/MarqueeAnnotator.tsx index cfdc648b4..d0516336c 100644 --- a/src/client/views/MarqueeAnnotator.tsx +++ b/src/client/views/MarqueeAnnotator.tsx @@ -66,7 +66,7 @@ export class MarqueeAnnotator extends ObservableReactComponent { if (!e.aborted && e.linkDocument) { Doc.GetProto(e.linkDocument).link_relationship = 'cropped image'; - Doc.GetProto(e.linkDocument).title = 'crop: ' + this.props.docView().Document.title; + Doc.GetProto(e.linkDocument).title = 'crop: ' + this.props.Document.title; Doc.GetProto(e.linkDocument).link_displayLine = false; } }, @@ -256,7 +256,7 @@ export class MarqueeAnnotator extends ObservableReactComponent (copy.style[prop as any] = marqueeStyle[prop as any])); copy.className = 'marqueeAnnotator-annotationBox'; copy.style.top = parseInt(marqueeStyle.top.toString().replace('px', '')) / scale + this.props.scrollTop + 'px'; diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx index 491a72c08..1cb5ff249 100644 --- a/src/client/views/StyleProvider.tsx +++ b/src/client/views/StyleProvider.tsx @@ -20,7 +20,6 @@ import { SnappingManager } from '../util/SnappingManager'; import { undoBatch, UndoManager } from '../util/UndoManager'; import { TreeSort } from './collections/TreeSort'; import { Colors } from './global/globalEnums'; -import { DocumentViewProps } from './nodes/DocumentView'; import { FieldViewProps } from './nodes/FieldView'; import { KeyValueBox } from './nodes/KeyValueBox'; import { PropertiesView } from './PropertiesView'; @@ -51,21 +50,7 @@ export enum StyleProp { } function toggleLockedPosition(doc: Doc) { - UndoManager.RunInBatch( - () => - runInAction(() => { - doc._lockedPosition = !doc._lockedPosition; - doc._pointerEvents = doc._lockedPosition ? 'none' : undefined; - }), - 'toggleBackground' - ); -} - -export function testDocProps(toBeDetermined: any): toBeDetermined is DocumentViewProps { - return toBeDetermined?.isContentActive ? toBeDetermined : undefined; -} -export function testFieldProps(toBeDetermined: any): toBeDetermined is FieldViewProps { - return toBeDetermined?.isContentActive ? toBeDetermined : undefined; + UndoManager.RunInBatch(() => Doc.toggleLockedPosition(doc), 'toggleBackground'); } export function wavyBorderPath(pw: number, ph: number, inset: number = 0.05) { @@ -82,19 +67,17 @@ export function wavyBorderPath(pw: number, ph: number, inset: number = 0.05) { // export function DefaultStyleProvider(doc: Opt, props: Opt, property: string): any { const remoteDocHeader = 'author;author_date;noMargin'; - const docProps = testDocProps(props) ? props : undefined; - const fieldProps = testFieldProps(props) ? props : undefined; const isCaption = property.includes(':caption'); const isAnchor = property.includes(':anchor'); const isNonTransparent = property.includes(':nonTransparent'); const isNonTransparentLevel = isNonTransparent ? Number(property.replace(/.*:nonTransparent([0-9]+).*/, '$1')) : 0; // property.includes(':nonTransparent'); const isContent = property.includes(':content'); const isAnnotated = property.includes(':annotated'); - const isInk = () => doc?._layout_isSvg && !docProps?.LayoutTemplateString; + const isInk = () => doc?._layout_isSvg && !props?.LayoutTemplateString; const isOpen = property.includes(':open'); const isEmpty = property.includes(':empty'); const boxBackground = property.includes(':box'); - const fieldKey = fieldProps?.fieldKey ? fieldProps.fieldKey + '_' : isCaption ? 'caption_' : ''; + const fieldKey = props?.fieldKey ? props.fieldKey + '_' : isCaption ? 'caption_' : ''; const lockedPosition = () => doc && BoolCast(doc._lockedPosition); const titleHeight = () => props?.styleProvider?.(doc, props, StyleProp.TitleHeight); const backgroundCol = () => props?.styleProvider?.(doc, props, StyleProp.BackgroundColor + ':nonTransparent' + (isNonTransparentLevel + 1)); @@ -137,20 +120,19 @@ export function DefaultStyleProvider(doc: Opt, props: Opt, return undefined; case StyleProp.DocContents:return undefined; case StyleProp.WidgetColor:return isAnnotated ? Colors.LIGHT_BLUE : 'dimgrey'; - case StyleProp.Opacity: return docProps?.LayoutTemplateString?.includes(KeyValueBox.name) ? 1 : doc?.text_inlineAnnotations ? 0 : Cast(doc?._opacity, "number", Cast(doc?.opacity, 'number', null)); + case StyleProp.Opacity: return props?.LayoutTemplateString?.includes(KeyValueBox.name) ? 1 : doc?.text_inlineAnnotations ? 0 : Cast(doc?._opacity, "number", Cast(doc?.opacity, 'number', null)); case StyleProp.FontSize: return StrCast(doc?.[fieldKey + 'fontSize'], StrCast(doc?._text_fontSize, StrCast(Doc.UserDoc().fontSize))); case StyleProp.FontFamily: return StrCast(doc?.[fieldKey + 'fontFamily'], StrCast(doc?._text_fontFamily, StrCast(Doc.UserDoc().fontFamily))); case StyleProp.FontWeight: return StrCast(doc?.[fieldKey + 'fontWeight'], StrCast(doc?._text_fontWeight, StrCast(Doc.UserDoc().fontWeight))); case StyleProp.FillColor: return StrCast(doc?._fillColor, StrCast(doc?.fillColor, 'transparent')); case StyleProp.ShowCaption:return doc?._type_collection === CollectionViewType.Carousel ? undefined: StrCast(doc?._layout_showCaption); - case StyleProp.TitleHeight: - return (props?.DocumentView?.().screenToViewTransform().Scale ?? 1) * NumCast(Doc.UserDoc().headerHeight,30) + case StyleProp.TitleHeight:return (props?.ScreenToLocalTransform().Scale ?? 1) * NumCast(Doc.UserDoc().headerHeight,30); case StyleProp.ShowTitle: return ( (doc && - !docProps?.LayoutTemplateString && + !props?.LayoutTemplateString && !doc.presentation_targetDoc && - !docProps?.LayoutTemplateString?.includes(KeyValueBox.name) && + !props?.LayoutTemplateString?.includes(KeyValueBox.name) && props?.layout_showTitle?.() !== '' && StrCast( doc._layout_showTitle, @@ -169,7 +151,6 @@ export function DefaultStyleProvider(doc: Opt, props: Opt, if (doc?.type === DocumentType.FONTICON) return SettingsManager.userColor; const docColor: Opt = StrCast(doc?.[fieldKey + 'color'], StrCast(doc?._color)); if (docColor) return docColor; - const parView = props?.DocumentView?.(); const backColor = backgroundCol(); return backColor ? lightOrDark(backColor) : undefined; case StyleProp.BorderRounding: @@ -247,7 +228,7 @@ export function DefaultStyleProvider(doc: Opt, props: Opt, doc?.layout_boxShadow, doc?._type_collection === CollectionViewType.Pile ? '4px 4px 10px 2px' - : lockedPosition() || doc?.isGroup || docProps?.LayoutTemplateString + : lockedPosition() || doc?.isGroup || props?.LayoutTemplateString ? undefined // groups have no drop shadow -- they're supposed to be "invisible". LayoutString's imply collection is being rendered as something else (e.g., title of a Slide) : `${Colors.DARK_GRAY} ${StrCast(doc.layout_boxShadow, '0.2vw 0.2vw 0.8vw')}` ); @@ -257,10 +238,10 @@ export function DefaultStyleProvider(doc: Opt, props: Opt, default: return doc.z ? `#9c9396 ${StrCast(doc?.layout_boxShadow, '10px 10px 0.9vw')}` // if it's a floating doc, give it a big shadow - : props?.DocumentView?.().containerViewPath?.().lastElement()?.Document._freeform_useClusters - ? `${backgroundCol()} ${StrCast(doc.layout_boxShadow, `0vw 0vw ${(lockedPosition() ? 100 : 50) / (docProps?.NativeDimScaling?.() || 1)}px`)}` // if it's just in a cluster, make the shadown roughly match the cluster border extent + : props?.containerViewPath?.().lastElement()?.Document._freeform_useClusters + ? `${backgroundCol()} ${StrCast(doc.layout_boxShadow, `0vw 0vw ${(lockedPosition() ? 100 : 50) / (props?.NativeDimScaling?.() || 1)}px`)}` // if it's just in a cluster, make the shadown roughly match the cluster border extent : NumCast(doc.group, -1) !== -1 - ? `gray ${StrCast(doc.layout_boxShadow, `0vw 0vw ${(lockedPosition() ? 100 : 50) / (docProps?.NativeDimScaling?.() || 1)}px`)}` // if it's just in a cluster, make the shadown roughly match the cluster border extent + ? `gray ${StrCast(doc.layout_boxShadow, `0vw 0vw ${(lockedPosition() ? 100 : 50) / (props?.NativeDimScaling?.() || 1)}px`)}` // if it's just in a cluster, make the shadown roughly match the cluster border extent : lockedPosition() ? undefined // if it's a background & has a cluster color, make the shadow spread really big : StrCast(doc.layout_fieldKey).includes('_inline') // if doc is an inline document in a text box @@ -271,8 +252,8 @@ export function DefaultStyleProvider(doc: Opt, props: Opt, } } case StyleProp.PointerEvents: - if (StrCast(doc?.pointerEvents) && !docProps?.LayoutTemplateString?.includes(KeyValueBox.name)) return StrCast(doc!.pointerEvents); // honor pointerEvents field (set by lock button usually) if it's not a keyValue view of the Doc - if (docProps?.DocumentView?.()._props.LayoutTemplateString?.includes(KeyValueBox.name)) return 'all'; + if (StrCast(doc?.pointerEvents) && !props?.LayoutTemplateString?.includes(KeyValueBox.name)) return StrCast(doc!.pointerEvents); // honor pointerEvents field (set by lock button usually) if it's not a keyValue view of the Doc + if (props?.LayoutTemplateString?.includes(KeyValueBox.name)) return 'all'; if (SnappingManager.ExploreMode || doc?.layout_unrendered) return isInk() ? 'visiblePainted' : 'all'; if (props?.pointerEvents?.() === 'none') return 'none'; if (opacity() === 0) return 'none'; @@ -281,22 +262,17 @@ export function DefaultStyleProvider(doc: Opt, props: Opt, if (props?.isDocumentActive?.() && !props.treeViewDoc) return isInk() ? 'visiblePainted' : 'all'; return undefined; // fixes problem with tree view elements getting pointer events when the tree view is not active case StyleProp.Decorations: - const lock = () => { - if (props?.DocumentView?.().containerViewPath?.().lastElement()?.Document?._type_collection === CollectionViewType.Freeform) { - return doc?.pointerEvents !== 'none' ? null : ( + const lock = () => doc?.pointerEvents !== 'none' ? null : (
toggleLockedPosition(doc)}>
); - } - }; const filter = () => { - const docView = props?.DocumentView?.(); const dashView = untracked(() => DocumentManager.Instance.getDocumentView(Doc.ActiveDashboard)); const showFilterIcon = StrListCast(doc?._childFilters).length || StrListCast(doc?._childFiltersByRanges).length ? 'green' // #18c718bd' //'hasFilter' - : docProps?.childFilters?.().filter(f => Utils.IsRecursiveFilter(f) && f !== Utils.noDragDocsFilter).length || docProps?.childFiltersByRanges().length + : props?.childFilters?.().filter(f => Utils.IsRecursiveFilter(f) && f !== Utils.noDragDocsFilter).length || props?.childFiltersByRanges().length ? 'orange' //'inheritsFilter' : undefined; return !showFilterIcon ? null : ( @@ -327,7 +303,7 @@ export function DefaultStyleProvider(doc: Opt, props: Opt, "this view inherits filters from one of its parents"} color={SettingsManager.userColor} background={showFilterIcon} - items={[ ...(dashView ? [dashView]: []), ...(docView?.containerViewPath?.()??[]), ...(docView ? [docView]:[])] + items={[ ...(dashView ? [dashView]: []), ...(props?.docViewPath?.()??[])] .filter(dv => StrListCast(dv?.Document.childFilters).length || StrListCast(dv?.Document.childRangeFilters).length) .map(dv => ({ text: StrCast(dv?.Document.title), diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx index 92c8e1256..363db8850 100644 --- a/src/client/views/collections/CollectionNoteTakingView.tsx +++ b/src/client/views/collections/CollectionNoteTakingView.tsx @@ -238,7 +238,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { PanelWidth={width} PanelHeight={height} styleProvider={this.styleProvider} - containerViewPath={this.docViewPath} + containerViewPath={this.childContainerViewPath} layout_fitWidth={this._props.childLayoutFitWidth} isContentActive={emptyFunction} onKey={this.onKeyDown} @@ -407,10 +407,9 @@ export class CollectionNoteTakingView extends CollectionSubView() { @undoBatch onKeyDown = (e: React.KeyboardEvent, fieldProps: FieldViewProps) => { - const docView = fieldProps.DocumentView?.(); - if (docView && (e.ctrlKey || docView.Document._createDocOnCR) && ['Enter'].includes(e.key)) { + if ((e.ctrlKey || fieldProps.Document._createDocOnCR) && ['Enter'].includes(e.key)) { e.stopPropagation?.(); - const newDoc = Doc.MakeCopy(docView.Document, true); + const newDoc = Doc.MakeCopy(fieldProps.Document, true); Doc.GetProto(newDoc).text = undefined; FormattedTextBox.SetSelectOnLoad(newDoc); return this.addDocument?.(newDoc); diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 0a0218124..9384b7088 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -278,16 +278,15 @@ export class CollectionStackingView extends CollectionSubView { - const docView = fieldProps.DocumentView?.(); - if (docView && ['Enter'].includes(e.key) && e.ctrlKey) { + if (['Enter'].includes(e.key) && e.ctrlKey) { e.stopPropagation?.(); const below = !e.altKey && e.key !== 'Tab'; - const layout_fieldKey = StrCast(docView.LayoutFieldKey); - const newDoc = Doc.MakeCopy(docView.Document, true); - const dataField = docView.Document[Doc.LayoutFieldKey(newDoc)]; + 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 (layout_fieldKey !== 'layout' && docView.Document[layout_fieldKey] instanceof Doc) { - newDoc[layout_fieldKey] = docView.Document[layout_fieldKey]; + if (layout_fieldKey !== 'layout' && fieldProps.Document[layout_fieldKey] instanceof Doc) { + newDoc[layout_fieldKey] = fieldProps.Document[layout_fieldKey]; } Doc.GetProto(newDoc).text = undefined; FormattedTextBox.SetSelectOnLoad(newDoc); @@ -327,7 +326,7 @@ export class CollectionStackingView extends CollectionSubView boolean; @@ -69,6 +70,9 @@ export function CollectionSubView(moreProps?: X) { : Doc.GetProto(this._props.Document); // if the layout document has a resolvedDataDoc, then we don't want to get its parent which would be the unexpanded template } + get childContainerViewPath() { + return this.DocumentView?.().docViewPath ?? returnEmptyDocViewList; + } // this returns whether either the collection is selected, or the template that it is part of is selected rootSelected = () => this._props.isSelected() || BoolCast(this._props.TemplateDataDocument && this._props.rootSelected?.()); diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index 2441c67e6..f00e42360 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -29,7 +29,7 @@ import { LightboxView } from '../LightboxView'; import { ObservableReactComponent } from '../ObservableReactComponent'; import { DefaultStyleProvider, StyleProp } from '../StyleProvider'; import { Colors } from '../global/globalEnums'; -import { DocFocusOptions, DocumentView, DocumentViewProps, OpenWhere, OpenWhereMod } from '../nodes/DocumentView'; +import { DocFocusOptions, DocumentView, OpenWhere, OpenWhereMod, returnEmptyDocViewList } from '../nodes/DocumentView'; import { KeyValueBox } from '../nodes/KeyValueBox'; import { DashFieldView } from '../nodes/formattedText/DashFieldView'; import { PinProps, PresBox, PresMovement } from '../nodes/trails'; @@ -595,7 +595,7 @@ export class TabMinimapView extends ObservableReactComponent { hideResizeHandles={this.treeView.outlineMode} styleProvider={this.titleStyleProvider} onClickScriptDisable="never" // tree docViews have a script to show fields, etc. - containerViewPath={this.treeView.docViewPath} + containerViewPath={this.treeView.childContainerViewPath} treeViewDoc={this.treeView.Document} addDocument={undefined} addDocTab={this._props.addDocTab} @@ -1084,7 +1084,7 @@ export class TreeView extends ObservableReactComponent { ScreenToLocalTransform={this.docTransform} renderDepth={this._props.renderDepth + 1} treeViewDoc={this.treeView?.Document} - containerViewPath={this.treeView.docViewPath} + containerViewPath={this.treeView.childContainerViewPath} childFilters={returnEmptyFilter} childFiltersByRanges={returnEmptyFilter} searchFilterDocs={returnEmptyDoclist} diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 3eaf1876c..c4358747b 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1170,18 +1170,17 @@ export class CollectionFreeFormView extends CollectionSubView { - const docView = fieldProps.DocumentView?.(); - if (docView && (e.metaKey || e.ctrlKey || e.altKey || docView.Document._createDocOnCR) && ['Tab', 'Enter'].includes(e.key)) { + 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(docView.LayoutFieldKey); - const newDoc = Doc.MakeCopy(docView.Document, true); - const dataField = docView.Document[Doc.LayoutFieldKey(newDoc)]; + 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(docView.Document.y) + NumCast(docView.Document._height) + 10; - else newDoc.x = NumCast(docView.Document.x) + NumCast(docView.Document._width) + 10; - if (layout_fieldKey !== 'layout' && docView.Document[layout_fieldKey] instanceof Doc) { - newDoc[layout_fieldKey] = docView.Document[layout_fieldKey]; + 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]; } Doc.GetProto(newDoc).text = undefined; FormattedTextBox.SetSelectOnLoad(newDoc); diff --git a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx index 4f4c674ea..72bdb9b6b 100644 --- a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx +++ b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx @@ -189,7 +189,7 @@ export class CollectionLinearView extends CollectionSubView() { dontRegisterView={BoolCast(this.Document.childDontRegisterViews)} focus={emptyFunction} styleProvider={this._props.styleProvider} - containerViewPath={this.docViewPath} + containerViewPath={this.childContainerViewPath} whenChildContentsActiveChanged={emptyFunction} bringToFront={emptyFunction} childFilters={this._props.childFilters} diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx index 1fd514ccb..40b4151fe 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx @@ -259,7 +259,7 @@ export class CollectionMulticolumnView extends CollectionSubView() { Document={childLayout} TemplateDataDocument={childLayout.resolvedDataDoc as Doc} styleProvider={this._props.styleProvider} - containerViewPath={this.docViewPath} + containerViewPath={this.childContainerViewPath} LayoutTemplate={this._props.childLayoutTemplate} LayoutTemplateString={this._props.childLayoutString} renderDepth={this._props.renderDepth + 1} diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx index 98e39cd36..04a4042f1 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx @@ -254,7 +254,7 @@ export class CollectionMultirowView extends CollectionSubView() { Document={layout} TemplateDataDocument={layout.resolvedDataDoc as Doc} styleProvider={this._props.styleProvider} - containerViewPath={this.docViewPath} + containerViewPath={this.childContainerViewPath} LayoutTemplate={this._props.childLayoutTemplate} LayoutTemplateString={this._props.childLayoutString} renderDepth={this._props.renderDepth + 1} diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss index 02131ae22..29d121974 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss +++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss @@ -210,8 +210,9 @@ border: 1px solid $medium-gray; overflow-x: hidden; overflow-y: auto; - padding: 5px; display: inline-flex; + padding: 0; + align-items: center; } .schema-row { diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx index e22a666c5..227274a53 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx @@ -971,7 +971,7 @@ class CollectionSchemaViewDoc extends ObservableReactComponent + : } + size={Size.XSMALL} + onPointerDown={e => + setupMoveUpEvents( + this, + e, + returnFalse, + emptyFunction, + undoable(e => { + e.stopPropagation(); + Doc.toggleLockedPosition(this.Document); + }, 'Delete Row') + ) + }> } diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 83cabf355..73709c17e 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -12,6 +12,7 @@ import { DocumentManager } from '../../util/DocumentManager'; import { ScriptingGlobals } from '../../util/ScriptingGlobals'; import { SelectionManager } from '../../util/SelectionManager'; import { DocComponent } from '../DocComponent'; +import { ObservableReactComponent } from '../ObservableReactComponent'; import { StyleProp } from '../StyleProvider'; import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView'; import './CollectionFreeFormDocumentView.scss'; @@ -37,7 +38,7 @@ export interface CollectionFreeFormDocumentViewWrapperProps extends DocumentView CollectionFreeFormView: CollectionFreeFormView; } @observer -export class CollectionFreeFormDocumentViewWrapper extends DocComponent() implements CollectionFreeFormDocumentViewProps { +export class CollectionFreeFormDocumentViewWrapper extends ObservableReactComponent implements CollectionFreeFormDocumentViewProps { constructor(props: any) { super(props); makeObservable(this); @@ -59,6 +60,9 @@ export class CollectionFreeFormDocumentViewWrapper extends DocComponent key.startsWith('w_')).map(key => key.replace('w_', '')) .map(key => ({upper:key, lower:key[0].toLowerCase() + key.substring(1)})); // prettier-ignore @@ -227,7 +231,7 @@ export class CollectionFreeFormDocumentView extends DocComponent { + float = () => { const topDoc = this.Document; const containerDocView = this._props.containerViewPath?.().lastElement(); const screenXf = containerDocView?.screenToContentsTransform(); @@ -253,8 +257,8 @@ export class CollectionFreeFormDocumentView extends DocComponent { const [locX, locY] = this._props.ScreenToLocalTransform().transformDirection(x, y); - this._props.Document.x = this._props.w_X() + locX; - this._props.Document.y = this._props.w_Y() + locY; + this.Document.x = this._props.w_X() + locX; + this.Document.y = this._props.w_Y() + locY; }; screenToLocalTransform = () => this._props @@ -288,7 +292,7 @@ export class CollectionFreeFormDocumentView extends DocComponent - {this._props.RenderCutoffProvider(this._props.Document) ? ( + {this._props.RenderCutoffProvider(this.Document) ? (
) : ( diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx index e707bb836..500eb52ac 100644 --- a/src/client/views/nodes/ComparisonBox.tsx +++ b/src/client/views/nodes/ComparisonBox.tsx @@ -11,7 +11,7 @@ import { undoBatch } from '../../util/UndoManager'; import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent'; import { StyleProp } from '../StyleProvider'; import './ComparisonBox.scss'; -import { DocumentView } from './DocumentView'; +import { DocumentView, returnEmptyDocViewList } from './DocumentView'; import { FieldView, FieldViewProps } from './FieldView'; import { PinProps, PresBox } from './trails'; @@ -152,6 +152,9 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent (doc instanceof Doc ? [doc] : doc).reduce((res, doc: Doc) => res && this.moveDoc(doc, addDoc, this.fieldKey + '_1'), true); moveDoc2 = (doc: Doc | Doc[], targetCol: Doc | undefined, addDoc: any) => (doc instanceof Doc ? [doc] : doc).reduce((res, doc: Doc) => res && this.moveDoc(doc, addDoc, this.fieldKey + '_2'), true); remDoc1 = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((res, doc) => res && this.remDoc(doc, this.fieldKey + '_1'), true); @@ -178,7 +181,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent { @observer export class DocumentContentsView extends ObservableReactComponent< FieldViewProps & { - layout_fieldKey: string; - LayoutTemplateString?: string; onClick?: () => ScriptField; LayoutTemplate?: () => Opt; } @@ -132,8 +130,8 @@ export class DocumentContentsView extends ObservableReactComponent< TraceMobx(); if (this._props.LayoutTemplateString) return this._props.LayoutTemplateString; if (!this.layoutDoc) return '

awaiting layout

'; - if (this._props.layout_fieldKey === 'layout_keyValue') return StrCast(this._props.Document.layout_keyValue, KeyValueBox.LayoutString()); - const layout = Cast(this.layoutDoc[this.layoutDoc === this._props.Document && this._props.layout_fieldKey ? this._props.layout_fieldKey : StrCast(this.layoutDoc.layout_fieldKey, 'layout')], 'string'); + if (this._props.fieldKey === 'layout_keyValue') return StrCast(this._props.Document.layout_keyValue, KeyValueBox.LayoutString()); + const layout = Cast(this.layoutDoc[this.layoutDoc === this._props.Document && this._props.fieldKey ? this._props.fieldKey : StrCast(this.layoutDoc.layout_fieldKey, 'layout')], 'string'); if (layout === undefined) return this._props.Document.data ? "" : KeyValueBox.LayoutString(); if (typeof layout === 'string') return layout; return '

Loading layout

'; @@ -141,12 +139,12 @@ export class DocumentContentsView extends ObservableReactComponent< get layoutDoc() { // bcz: replaced this with below : is it correct? change was made to accommodate passing fieldKey's from a layout script - // const template: Doc = this._props.LayoutTemplate?.() || Doc.Layout(this._props.Document, this._props.layout_fieldKey ? Cast(this._props.Document[this._props.layout_fieldKey], Doc, null) : undefined); + // const template: Doc = this._props.LayoutTemplate?.() || Doc.Layout(this._props.Document, this._props.fieldKey ? Cast(this._props.Document[this._props.fieldKey], Doc, null) : undefined); const template: Doc = this._props.LayoutTemplate?.() || (this._props.LayoutTemplateString && this._props.Document) || - (this._props.layout_fieldKey && StrCast(this._props.Document[this._props.layout_fieldKey]) && this._props.Document) || - Doc.Layout(this._props.Document, this._props.layout_fieldKey ? Cast(this._props.Document[this._props.layout_fieldKey], Doc, null) : undefined); + (this._props.fieldKey && StrCast(this._props.Document[this._props.fieldKey]) && this._props.Document) || + Doc.Layout(this._props.Document, this._props.fieldKey ? Cast(this._props.Document[this._props.fieldKey], Doc, null) : undefined); return Doc.expandTemplateLayout(template, this._props.Document); } diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 4e13b0ccb..444c300f3 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -89,6 +89,9 @@ export enum OpenWhere { addRightKeyvalue = 'add:right:keyValue', } +export function returnEmptyDocViewList() { + return [] as DocumentView[]; +} export interface DocFocusOptions { willPan?: boolean; // determines whether to pan to target document willZoomCentered?: boolean; // determines whether to zoom in on target document. if zoomScale is 0, this just centers the document @@ -148,6 +151,7 @@ export interface DocComponentView { * */ export interface DocumentViewSharedProps { Document: Doc; + LayoutTemplateString?: string; TemplateDataDocument?: Doc; renderDepth: number; scriptContext?: any; // can be assigned anything and will be passed as 'scriptContext' to any OnClick script that executes on this document @@ -161,6 +165,7 @@ export interface DocumentViewSharedProps { ignoreAutoHeight?: boolean; disableBrushing?: boolean; // should highlighting for this view be disabled when same document in another view is hovered over. CollectionFreeFormDocumentView?: () => CollectionFreeFormDocumentView; + containerViewPath?: () => DocumentView[]; fitContentsToBox?: () => boolean; // used by freeformview to fit its contents to its panel. corresponds to _freeform_fitContentsToBox property on a Document isGroupActive?: () => string | undefined; // is this document part of a group that is active setContentView?: (view: DocComponentView) => any; @@ -206,7 +211,6 @@ export interface DocumentViewProps extends DocumentViewSharedProps { hideLinkButton?: boolean; hideCaptions?: boolean; contentPointerEvents?: 'none' | 'all' | undefined; // pointer events allowed for content of a document view. eg. set to "none" in menuSidebar for sharedDocs so that you can select a document, but not interact with its contents - LayoutTemplateString?: string; dontCenter?: 'x' | 'y' | 'xy'; childHideDecorationTitle?: boolean; childHideResizeHandles?: boolean; @@ -218,7 +222,6 @@ export interface DocumentViewProps extends DocumentViewSharedProps { NativeWidth?: () => number; NativeHeight?: () => number; LayoutTemplate?: () => Opt; - containerViewPath?: () => DocumentView[]; contextMenuItems?: () => { script: ScriptField; filter?: ScriptField; label: string; icon: string }[]; onClick?: () => ScriptField; onDoubleClick?: () => ScriptField; @@ -235,13 +238,13 @@ export interface DocumentViewProps extends DocumentViewSharedProps { * these props correspond to things that the DocumentView creates and thus doesn't need to receive as a prop */ export interface DocumentViewInternalSharedProps { - DocumentView: () => DocumentView; select: (ctrlPressed: boolean, shiftPress?: boolean) => void; isSelected: () => boolean; + docViewPath: () => DocumentView[]; NativeDimScaling?: () => number; // scaling the DocumentView does to transform its contents into its panel & needed by ScreenToLocal } export interface DocumentViewInternalProps extends DocumentViewProps, DocumentViewInternalSharedProps { - docViewPath: () => DocumentView[]; + docViewPublic: () => DocumentView; } @observer @@ -276,7 +279,7 @@ export class DocumentViewInternal extends DocComponent { - const targetMatch = - Doc.AreProtosEqual(anchor, this.Document) || // anchor is this document, so anchor's properties apply to this document - (DocCast(anchor)?.layout_unrendered && Doc.AreProtosEqual(DocCast(anchor.annotationOn), this.Document)) // the anchor is an layout_unrendered annotation on this document, so anchor properties apply to this document - ? true - : false; - return targetMatch && PresBox.restoreTargetDocView(docView, anchor, focusSpeed) ? focusSpeed : undefined; - }; - // switches text input focus to the title bar of the document (and displays the title bar if it hadn't been) setTitleFocus = () => { if (!StrCast(this.layoutDoc._layout_showTitle)) this.layoutDoc._layout_showTitle = 'title'; @@ -923,8 +917,8 @@ export class DocumentViewInternal extends DocComponent {this.layoutDoc.layout_hideAllLinks ? null : this.allLinkEndpoints}
@@ -1699,7 +1692,7 @@ export class DocumentView extends ObservableReactComponent { }}> span { + max-height: 100%; // make sure top of text is in view, otherwise it would center on middle of large text span + } } .labelBox-params { @@ -29,4 +32,4 @@ width: 100%; background: lightgray; border: dimgray solid 1px; -} \ No newline at end of file +} diff --git a/src/client/views/nodes/LabelBox.tsx b/src/client/views/nodes/LabelBox.tsx index 934bce448..cc7c15a10 100644 --- a/src/client/views/nodes/LabelBox.tsx +++ b/src/client/views/nodes/LabelBox.tsx @@ -1,7 +1,7 @@ import { action, computed, makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; -import { Doc, DocListCast } from '../../../fields/Doc'; +import { Doc, DocListCast, Field } from '../../../fields/Doc'; import { List } from '../../../fields/List'; import { listSpec } from '../../../fields/Schema'; import { BoolCast, Cast, NumCast, StrCast } from '../../../fields/Types'; @@ -43,7 +43,7 @@ export class LabelBox extends ViewBoxBaseComponent { diff --git a/src/client/views/nodes/LinkAnchorBox.tsx b/src/client/views/nodes/LinkAnchorBox.tsx index 864c1955b..362a7def1 100644 --- a/src/client/views/nodes/LinkAnchorBox.tsx +++ b/src/client/views/nodes/LinkAnchorBox.tsx @@ -33,15 +33,16 @@ export class LinkAnchorBox extends ViewBoxBaseComponent { const linkSource = this.linkSource; - linkSource && setupMoveUpEvents(this, e, this.onPointerMove, emptyFunction, (e, doubleTap) => { - if (doubleTap) LinkFollower.FollowLink(this.Document, linkSource, false); - else this._props.select(false); - }); + linkSource && + setupMoveUpEvents(this, e, this.onPointerMove, emptyFunction, (e, doubleTap) => { + if (doubleTap) LinkFollower.FollowLink(this.Document, linkSource, false); + else this._props.select(false); + }); }; onPointerMove = action((e: PointerEvent, down: number[], delta: number[]) => { const cdiv = this._ref?.current?.parentElement; diff --git a/src/client/views/nodes/LinkBox.tsx b/src/client/views/nodes/LinkBox.tsx index 4221f464d..ba34255dc 100644 --- a/src/client/views/nodes/LinkBox.tsx +++ b/src/client/views/nodes/LinkBox.tsx @@ -29,12 +29,12 @@ export class LinkBox extends ViewBoxBaseComponent() { @computed get anchor1() { const anchor1 = DocCast(this.dataDoc.link_anchor_1); const anchor_1 = anchor1?.layout_unrendered ? DocCast(anchor1.annotationOn) : anchor1; - return DocumentManager.Instance.getDocumentView(anchor_1, this.containerViewPath?.().lastElement()); + return DocumentManager.Instance.getDocumentView(anchor_1, this.DocumentView?.().containerViewPath?.().lastElement()); } @computed get anchor2() { const anchor2 = DocCast(this.dataDoc.link_anchor_2); const anchor_2 = anchor2?.layout_unrendered ? DocCast(anchor2.annotationOn) : anchor2; - return DocumentManager.Instance.getDocumentView(anchor_2, this.containerViewPath?.().lastElement()); + return DocumentManager.Instance.getDocumentView(anchor_2, this.DocumentView?.().containerViewPath?.().lastElement()); } screenBounds = () => { if (this.layoutDoc._layout_isSvg && this.anchor1 && this.anchor2 && this.anchor1.CollectionFreeFormView) { @@ -66,7 +66,7 @@ export class LinkBox extends ViewBoxBaseComponent() { const a = (this.anchor1 ?? this.anchor2)!; const b = (this.anchor2 ?? this.anchor1)!; - const parxf = this.containerViewPath?.().lastElement().ComponentView as CollectionFreeFormView; + const parxf = this.DocumentView?.().containerViewPath?.().lastElement().ComponentView as CollectionFreeFormView; const this_xf = parxf?.screenToFreeformContentsXf ?? Transform.Identity; //this.ScreenToLocalTransform(); const a_invXf = a.screenToViewTransform().inverse(); const b_invXf = b.screenToViewTransform().inverse(); diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 71c1b6a4c..7696a45a0 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -581,6 +581,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent Object.values(this._disposers).forEach(disposer => disposer?.()); isContentActive = () => this._props.tbox._props.isContentActive() || this._props.tbox.isAnyChildContentActive?.(); @@ -207,7 +210,7 @@ export class DashDocViewInternal extends ObservableReactComponent { - let container = this._props.tbox.containerViewPath?.().lastElement(); + let container = this._props.tbox.DocumentView?.().containerViewPath?.().lastElement(); if (container) { const embedding = Doc.MakeEmbedding(container.Document); embedding._type_collection = CollectionViewType.Time; diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx index 8cf01b9de..4bc79176e 100644 --- a/src/client/views/nodes/trails/PresElementBox.tsx +++ b/src/client/views/nodes/trails/PresElementBox.tsx @@ -50,7 +50,7 @@ export class PresElementBox extends ViewBoxBaseComponent() { // the presentation view that renders this slide @computed get presBoxView() { - return this.containerViewPath?.().lastElement()?.ComponentView as PresBox; + return this.DocumentView?.().containerViewPath?.().lastElement()?.ComponentView as PresBox; } // the presentation view document that renders this slide diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 89e5944f2..01590749e 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -21,11 +21,12 @@ import { DocFocusOptions, DocumentViewProps } from '../nodes/DocumentView'; import { FieldViewProps } from '../nodes/FieldView'; import { LinkInfo } from '../nodes/LinkDocPreview'; import { ObservableReactComponent } from '../ObservableReactComponent'; -import { StyleProp, testDocProps } from '../StyleProvider'; +import { StyleProp } from '../StyleProvider'; import { AnchorMenu } from './AnchorMenu'; import { Annotation } from './Annotation'; import { GPTPopup } from './GPTPopup/GPTPopup'; import './PDFViewer.scss'; +import { PDFBox } from '../nodes/PDFBox'; const _global = (window /* browser */ || global) /* node */ as any; //pdfjsLib.GlobalWorkerOptions.workerSrc = `/assets/pdf.worker.js`; @@ -33,6 +34,7 @@ const _global = (window /* browser */ || global) /* node */ as any; Pdfjs.GlobalWorkerOptions.workerSrc = 'https://unpkg.com/pdfjs-dist@4.0.379/build/pdf.worker.mjs'; interface IViewerProps extends FieldViewProps { + pdfBox: PDFBox; Document: Doc; dataDoc: Doc; layoutDoc: Doc; @@ -313,7 +315,7 @@ export class PDFViewer extends ObservableReactComponent { this._ignoreScroll = false; if (this._scrollTimer) clearTimeout(this._scrollTimer); // wait until a scrolling pause, then create an anchor to audio this._scrollTimer = setTimeout(() => { - DocUtils.MakeLinkToActiveAudio(() => this._props.DocumentView?.().ComponentView?.getAnchor!(true)!, false); + DocUtils.MakeLinkToActiveAudio(() => this._props.pdfBox.getAnchor(true)!, false); this._scrollTimer = undefined; }, 200); } @@ -419,7 +421,7 @@ export class PDFViewer extends ObservableReactComponent { @action createTextAnnotation = (sel: Selection, selRange: Range) => { if (this._mainCont.current) { - this._mainCont.current.style.transform = `rotate(${NumCast(this._props.DocumentView!().screenToContentsTransform().RotateDeg)}deg)`; + this._mainCont.current.style.transform = `rotate(${NumCast(this._props.pdfBox.ScreenToLocalBoxXf().RotateDeg)}deg)`; const boundingRect = this._mainCont.current.getBoundingClientRect(); const clientRects = selRange.getClientRects(); for (let i = 0; i < clientRects.length; i++) { @@ -499,9 +501,8 @@ export class PDFViewer extends ObservableReactComponent { opaqueFilter = () => [...this._props.childFilters(), Utils.noDragDocsFilter, ...(SnappingManager.CanEmbed && this._props.isContentActive() ? [] : [Utils.OpaqueBackgroundFilter])]; childStyleProvider = (doc: Doc | undefined, props: Opt, property: string): any => { if (doc instanceof Doc && property === StyleProp.PointerEvents) { - const docProps = testDocProps(props) ? props : undefined; if (this.inlineTextAnnotations.includes(doc) || this._props.isContentActive() === false) return 'none'; - const isInk = doc.layout_isSvg && !docProps?.LayoutTemplateString; + const isInk = doc.layout_isSvg && !props?.LayoutTemplateString; return isInk ? 'visiblePainted' : 'all'; } return this._props.styleProvider?.(doc, props, property); @@ -589,7 +590,7 @@ export class PDFViewer extends ObservableReactComponent { isNativeScaled={true} annotationLayerScrollTop={NumCast(this._props.Document._layout_scrollTop)} addDocument={this.addDocumentWrapper} - docView={this._props.DocumentView!} + docView={this._props.pdfBox.DocumentView!} finishMarquee={this.finishMarquee} savedAnnotations={this.savedAnnotations} selectionText={this.selectionText} diff --git a/src/client/views/topbar/TopBar.tsx b/src/client/views/topbar/TopBar.tsx index 188b2eba4..5828313c8 100644 --- a/src/client/views/topbar/TopBar.tsx +++ b/src/client/views/topbar/TopBar.tsx @@ -22,7 +22,7 @@ import { CollectionDockingView } from '../collections/CollectionDockingView'; import { CollectionLinearView } from '../collections/collectionLinear'; import { DashboardView } from '../DashboardView'; import { Colors } from '../global/globalEnums'; -import { DocumentViewInternal } from '../nodes/DocumentView'; +import { DocumentViewInternal, returnEmptyDocViewList } from '../nodes/DocumentView'; import { DefaultStyleProvider } from '../StyleProvider'; import './TopBar.scss'; @@ -100,6 +100,7 @@ export class TopBar extends React.Component {
Date: Wed, 31 Jan 2024 20:39:47 -0500 Subject: cleaned up accessing/setting proto_embeddings with api on Doc. fixed some css related to IconButtons. added a paintView toggle button to dec decorations for text with code blocks. enabled text with code to modify Docs and get this and documentView as params. --- package-lock.json | 9 +- package.json | 2 +- src/client/util/DocumentManager.ts | 4 +- src/client/util/DropConverter.ts | 1 + src/client/util/Scripting.ts | 3 +- src/client/views/DocComponent.tsx | 2 +- src/client/views/DocumentDecorations.tsx | 2 +- src/client/views/PropertiesDocContextSelector.tsx | 6 +- src/client/views/PropertiesView.tsx | 5 +- src/client/views/StyleProvider.scss | 4 + src/client/views/StyleProvider.tsx | 18 +++- .../views/collections/CollectionDockingView.tsx | 2 +- src/client/views/collections/TreeView.scss | 4 + .../collectionFreeForm/CollectionFreeFormView.tsx | 14 ++- .../collectionSchema/CollectionSchemaView.scss | 7 +- .../collections/collectionSchema/SchemaRowBox.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 6 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 55 +++++----- .../views/nodes/formattedText/PaintButtonView.tsx | 113 --------------------- .../views/nodes/formattedText/RichTextRules.ts | 49 +++------ src/fields/Doc.ts | 25 +++-- 21 files changed, 127 insertions(+), 206 deletions(-) delete mode 100644 src/client/views/nodes/formattedText/PaintButtonView.tsx (limited to 'src/client/views/collections/collectionSchema/CollectionSchemaView.scss') diff --git a/package-lock.json b/package-lock.json index aa4108243..aafc14a86 100644 --- a/package-lock.json +++ b/package-lock.json @@ -154,7 +154,7 @@ "prosemirror-commands": "^1.5.2", "prosemirror-find-replace": "^0.9.0", "prosemirror-history": "^1.3.2", - "prosemirror-inputrules": "github:bobzel/prosemirror-inputrules#3b3b3e0b1a1dcf80490d81675206369b6be96276", + "prosemirror-inputrules": "^1.4.0", "prosemirror-keymap": "^1.2.2", "prosemirror-model": "^1.19.3", "prosemirror-schema-list": "^1.3.0", @@ -28699,10 +28699,9 @@ } }, "node_modules/prosemirror-inputrules": { - "version": "1.3.0", - "resolved": "git+ssh://git@github.com/bobzel/prosemirror-inputrules.git#3b3b3e0b1a1dcf80490d81675206369b6be96276", - "integrity": "sha512-l81tcwS7ugPJEvCy78RtEvR2/2mVaTkFHJD9ACRxRDXhrfPWV0FkFYBAO7GolN4XlzIbIsal2MVvq2baLQ2guw==", - "license": "MIT", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/prosemirror-inputrules/-/prosemirror-inputrules-1.4.0.tgz", + "integrity": "sha512-6ygpPRuTJ2lcOXs9JkefieMst63wVJBgHZGl5QOytN7oSZs3Co/BYbc3Yx9zm9H37Bxw8kVzCnDsihsVsL4yEg==", "dependencies": { "prosemirror-state": "^1.0.0", "prosemirror-transform": "^1.0.0" diff --git a/package.json b/package.json index f8144a0b3..a94f8c9be 100644 --- a/package.json +++ b/package.json @@ -237,7 +237,7 @@ "prosemirror-commands": "^1.5.2", "prosemirror-find-replace": "^0.9.0", "prosemirror-history": "^1.3.2", - "prosemirror-inputrules": "github:bobzel/prosemirror-inputrules#3b3b3e0b1a1dcf80490d81675206369b6be96276", + "prosemirror-inputrules": "^1.4.0", "prosemirror-keymap": "^1.2.2", "prosemirror-model": "^1.19.3", "prosemirror-schema-list": "^1.3.0", diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index f730d17fe..53d472c66 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -355,8 +355,8 @@ export function DocFocusOrOpen(doc: Doc, options: FocusViewOptions = { willZoomC }); } }; - if (Doc.IsDataProto(doc) && DocListCast(doc.proto_embeddings).some(embed => embed.hidden && [AclAdmin, AclEdit].includes(GetEffectiveAcl(embed)))) { - doc = DocListCast(doc.proto_embeddings).find(embed => embed.hidden && [AclAdmin, AclEdit].includes(GetEffectiveAcl(embed)))!; + if (Doc.IsDataProto(doc) && Doc.GetEmbeddings(doc).some(embed => embed.hidden && [AclAdmin, AclEdit].includes(GetEffectiveAcl(embed)))) { + doc = Doc.GetEmbeddings(doc).find(embed => embed.hidden && [AclAdmin, AclEdit].includes(GetEffectiveAcl(embed)))!; } if (doc.hidden) { doc.hidden = false; diff --git a/src/client/util/DropConverter.ts b/src/client/util/DropConverter.ts index ba981145d..54066d267 100644 --- a/src/client/util/DropConverter.ts +++ b/src/client/util/DropConverter.ts @@ -73,6 +73,7 @@ export function convertDropDataToButtons(data: DragManager.DocumentDragData) { _nativeHeight: 100, _width: 100, _height: 100, + _layout_hideContextMenu: true, backgroundColor: StrCast(doc.backgroundColor), title: StrCast(layoutDoc.title), btnType: ButtonType.ClickButton, diff --git a/src/client/util/Scripting.ts b/src/client/util/Scripting.ts index dfaacf318..f5e162d16 100644 --- a/src/client/util/Scripting.ts +++ b/src/client/util/Scripting.ts @@ -61,7 +61,8 @@ function Run(script: string | undefined, customParams: string[], diagnostics: an const compiledFunction = (() => { try { return new Function(...paramNames, `return ${script}`); - } catch { + } catch (e) { + console.log(e); return undefined; } })(); diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index 73fa6709c..58be41f53 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -189,7 +189,7 @@ export function ViewBoxAnnotatableComponent

() { toRemove.forEach(doc => { leavePushpin && DocUtils.LeavePushpin(doc, annotationKey ?? this.annotationKey); Doc.RemoveDocFromList(targetDataDoc, annotationKey ?? this.annotationKey, doc, true); - Doc.RemoveDocFromList(doc[DocData], 'proto_embeddings', doc, true); + Doc.RemoveEmbedding(doc, doc); doc.embedContainer = undefined; if (recent && !dontAddToRemoved) { doc.type !== DocumentType.LOADING && Doc.AddDocToList(recent, 'data', doc, undefined, true, true); diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 2193acf62..dec109d7b 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -283,7 +283,7 @@ export class DocumentDecorations extends ObservableReactComponent !embedding.embedContainer) ?? Doc.MakeEmbedding(openDoc); + openDoc = Doc.GetEmbeddings(openDoc).find(embedding => !embedding.embedContainer) ?? Doc.MakeEmbedding(openDoc); Doc.deiconifyView(openDoc); } LightboxView.Instance.SetLightboxDoc( diff --git a/src/client/views/PropertiesDocContextSelector.tsx b/src/client/views/PropertiesDocContextSelector.tsx index 54f141a36..361451c4d 100644 --- a/src/client/views/PropertiesDocContextSelector.tsx +++ b/src/client/views/PropertiesDocContextSelector.tsx @@ -28,14 +28,14 @@ export class PropertiesDocContextSelector extends ObservableReactComponent embedding.embedContainer && embedding.embedContainer instanceof Doc).reduce((set, embedding) => set.add(Cast(embedding.embedContainer, Doc, null)), new Set()); - const containerSets = Array.from(containerProtos.keys()).map(container => DocListCast(container.proto_embeddings)); + const containerSets = Array.from(containerProtos.keys()).map(container => Doc.GetEmbeddings(container)); const containers = containerSets.reduce((p, set) => { set.map(s => p.add(s)); return p; }, new Set()); - const doclayoutSets = Array.from(containers.keys()).map(dp => DocListCast(dp.proto_embeddings)); + const doclayoutSets = Array.from(containers.keys()).map(dp => Doc.GetEmbeddings(dp)); const doclayouts = Array.from( doclayoutSets .reduce((p, set) => { diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx index 208ed56c9..a7a065a95 100644 --- a/src/client/views/PropertiesView.tsx +++ b/src/client/views/PropertiesView.tsx @@ -173,7 +173,7 @@ export class PropertiesView extends ObservableReactComponent(reqdKeys); const docs: Doc[] = SelectionManager.Views.length < 2 ? [this.layoutFields ? Doc.Layout(this.selectedDoc) : this.dataDoc] : SelectionManager.Views.map(dv => (this.layoutFields ? dv.layoutDoc : dv.dataDoc)); - docs.forEach(doc => Object.keys(doc).forEach(key => doc[key] !== ComputedField.undefined && ids.add(key))); + docs.forEach(doc => Object.keys(doc).forEach(key => doc[key] !== ComputedField.undefined && key && ids.add(key))); // prettier-ignore Array.from(ids).filter(filter).sort().map(key => { @@ -263,8 +263,7 @@ export class PropertiesView extends ObservableReactComponent Doc.toggleLockedPosition(doc), 'toggleBackground'); } +function togglePaintView(e: React.MouseEvent, doc: Opt, props: Opt) { + const scriptProps = { + this: doc, + _readOnly_: false, + documentView: props?.DocumentView?.(), + value: undefined, + }; + e.stopPropagation(); + UndoManager.RunInBatch(() => doc && ScriptCast(doc.onPaint).script.run(scriptProps), 'togglePaintView'); +} export function wavyBorderPath(pw: number, ph: number, inset: number = 0.05) { return `M ${pw * 0.5} ${ph * inset} C ${pw * 0.6} ${ph * inset} ${pw * (1 - 2 * inset)} 0 ${pw * (1 - inset)} ${ph * inset} C ${pw} ${ph * (2 * inset)} ${pw * (1 - inset)} ${ph * 0.25} ${pw * (1 - inset)} ${ph * 0.3} C ${ @@ -267,6 +277,11 @@ export function DefaultStyleProvider(doc: Opt, props: Opt

); + const paint = () => !doc?.onPaint ? null : ( +
togglePaintView(e, doc, props)}> + +
+ ); const filter = () => { const dashView = untracked(() => DocumentManager.Instance.getDocumentView(Doc.ActiveDashboard)); const showFilterIcon = @@ -329,6 +344,7 @@ export function DefaultStyleProvider(doc: Opt, props: Opt + {paint()} {lock()} {filter()} {audio()} diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 87973fd81..31ca86f0f 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -490,7 +490,7 @@ export class CollectionDockingView extends CollectionSubView() { // if you close a tab that is not embedded somewhere else (an embedded Doc can be opened simultaneously in a tab), then add the tab to recently closed if (tab.DashDoc.embedContainer === this.Document) tab.DashDoc.embedContainer = undefined; if (!tab.DashDoc.embedContainer) Doc.AddDocToList(Doc.MyRecentlyClosed, 'data', tab.DashDoc, undefined, true, true); - Doc.RemoveDocFromList(tab.DashDoc[DocData], 'proto_embeddings', tab.DashDoc); + Doc.RemoveEmbedding(tab.DashDoc, tab.DashDoc); } if (CollectionDockingView.Instance) { const dview = CollectionDockingView.Instance.Document; diff --git a/src/client/views/collections/TreeView.scss b/src/client/views/collections/TreeView.scss index 0a1946f09..09701ddb5 100644 --- a/src/client/views/collections/TreeView.scss +++ b/src/client/views/collections/TreeView.scss @@ -128,6 +128,10 @@ position: relative; z-index: 1; + .treeView-rightButtons > .iconButton-container { + min-height: unset; + } + .treeView-background { width: 100%; height: 100%; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 54e8b08b6..9368560e9 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -54,6 +54,7 @@ import { CollectionFreeFormRemoteCursors } from './CollectionFreeFormRemoteCurso import './CollectionFreeFormView.scss'; import { MarqueeView } from './MarqueeView'; import { RichTextField } from '../../../../fields/RichTextField'; +import { CompileScript } from '../../../util/Scripting'; export interface collectionFreeformViewProps { NativeWidth?: () => number; @@ -80,8 +81,10 @@ export class CollectionFreeFormView extends CollectionSubView { ${paintFunc} })()`; + : paintFunc.includes('dashDiv') + ? `const dashDiv = document.querySelector('#${this._paintedId}'); + (async () => { ${paintFunc} })()` + : paintFunc; } constructor(props: any) { super(props); @@ -1496,7 +1499,12 @@ export class CollectionFreeFormView extends CollectionSubView ({ code: this.paintFunc, first: this._firstRender, width: this.Document._width, height: this.Document._height }), - ({ code, first }) => code && !first && eval(code), + ({ code, first }) => { + if (!code.includes('dashDiv')) { + const script = CompileScript(code, { params: { docView: 'any' }, typecheck: false, editable: true }); + if (script.compiled) script.run({ this: this.Document, docView: this.DocumentView?.() }); + } else code && !first && eval(code); + }, { fireImmediately: true } ); diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss index 29d121974..29491569a 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss +++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss @@ -128,7 +128,7 @@ .row-menu { display: flex; - justify-content: flex-end; + justify-content: center; } } @@ -224,7 +224,10 @@ display: flex; flex-direction: row; min-width: 50px; - justify-content: flex-end; + justify-content: center; + .iconButton-container { + min-width: unset !important; + } } .row-cells { diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx index f2fe0dde7..39fea2d2e 100644 --- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx +++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx @@ -121,7 +121,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent() { pointerEvents: !this._props.isContentActive() ? 'none' : undefined, }}> : } size={Size.XSMALL} onPointerDown={e => diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 51f4b1a68..b5355fb99 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -456,8 +456,8 @@ export class DocumentViewInternal extends DocComponent this._props.removeDocument?.(this.Document), 'delete doc'); setToggleDetail = undoable( - (defaultLayout: string) => - (this.Document.onClick = ScriptField.MakeScript( + (defaultLayout: string, scriptFieldKey: 'onClick') => + (this.Document[scriptFieldKey] = ScriptField.MakeScript( `toggleDetail(documentView, "${StrCast(this.Document.layout_fieldKey) .replace('layout_', '') .replace(/^layout$/, 'detail')}", "${defaultLayout}")`, @@ -1212,7 +1212,7 @@ export class DocumentView extends DocComponent() { }; public noOnClick = () => this._docViewInternal?.noOnClick(); public toggleFollowLink = (zoom?: boolean, setTargetToggle?: boolean): void => this._docViewInternal?.toggleFollowLink(zoom, setTargetToggle); - public setToggleDetail = (defaultLayout = '') => this._docViewInternal?.setToggleDetail(defaultLayout); + public setToggleDetail = (defaultLayout = '', scriptFieldKey = 'onClick') => this._docViewInternal?.setToggleDetail(defaultLayout, scriptFieldKey); public onContextMenu = (e?: React.MouseEvent, pageX?: number, pageY?: number) => this._docViewInternal?.onContextMenu?.(e, pageX, pageY); public cleanupPointerEvents = () => this._docViewInternal?.cleanupPointerEvents(); public startDragging = (x: number, y: number, dropAction: dropActionType, hideSource = false) => this._docViewInternal?.startDragging(x, y, dropAction, hideSource); diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 973f90501..b82ab4219 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -67,8 +67,6 @@ import { RichTextMenu, RichTextMenuPlugin } from './RichTextMenu'; import { RichTextRules } from './RichTextRules'; import { schema } from './schema_rts'; import { SummaryView } from './SummaryView'; -import { CollectionView } from '../../collections/CollectionView'; -import { PaintButtonView } from './PaintButtonView'; // import * as applyDevTools from 'prosemirror-dev-tools'; @observer export class FormattedTextBox extends ViewBoxAnnotatableComponent() implements ViewBoxInterface { @@ -488,14 +486,29 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent, or ^@ + * The last of these is interpreted as an include directive when converting the text into evaluated code in the paint + * function of a freeform view that is driven by the text box's text. The include directive will copy the code of the published + * document into the code being evaluated. + */ hyperlinkTerm = (tr: any, target: Doc, newAutoLinks: Set) => { const editorView = this._editorView; if (editorView && (editorView as any).docView && !Doc.AreProtosEqual(target, this.Document)) { const autoLinkTerm = StrCast(target.title).replace(/^@/, ''); var alink: Doc | undefined; this.findInNode(editorView, editorView.state.doc, autoLinkTerm).forEach(sel => { - const splitter = editorView.state.schema.marks.splitter.create({ id: Utils.GenerateGuid() }); - if (!sel.$anchor.pos || [autoLinkTerm, StrCast(target.title)].includes(editorView.state.doc.textBetween(sel.$anchor.pos - 1, sel.$to.pos).trim())) { + if ( + !sel.$anchor.pos || + autoLinkTerm === + editorView.state.doc + .textBetween(sel.$anchor.pos - 1, sel.$to.pos) + .trim() + .replace(/[\^@]+/, '') + ) { + const splitter = editorView.state.schema.marks.splitter.create({ id: Utils.GenerateGuid() }); tr = tr.addMark(sel.from, sel.to, splitter); tr.doc.nodesBetween(sel.from, sel.to, (node: any, pos: number, parent: any) => { if (node.firstChild === null && !node.marks.find((m: Mark) => m.type.name === schema.marks.noAutoLinkAnchor.name) && node.marks.find((m: Mark) => m.type.name === schema.marks.splitter.name)) { @@ -668,12 +681,22 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent -1) { - const sel = new TextSelection(pm.state.doc.resolve(ep.from + index + foundAt + 1), pm.state.doc.resolve(ep.from + index + foundAt + find.length + 1)); - ret.push(sel); - index = index + foundAt + find.length; + var blockOffset = 0; + for (var i = 0; i < node.childCount; i++) { + var textContent = ''; + while (i < node.childCount && node.child(i).type === pm.state.schema.nodes.text) { + textContent += node.child(i).textContent; + i++; + } + while (ep && (foundAt = textContent.slice(index).search(regexp)) > -1) { + const sel = new TextSelection(pm.state.doc.resolve(ep.from + index + blockOffset + foundAt + 1), pm.state.doc.resolve(ep.from + index + blockOffset + foundAt + find.length + 1)); + ret.push(sel); + index = index + foundAt + find.length; + } + blockOffset += textContent.length; + if (i < node.childCount) blockOffset += node.child(i).nodeSize; } } } else { @@ -934,17 +957,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent (this.layoutDoc._createDocOnCR = !this.layoutDoc._createDocOnCR), icon: !this.Document._createDocOnCR ? 'grip-lines' : 'bars', }); - optionItems.push({ - description: 'Make Paint Function', - event: () => { - this.dataDoc.layout_painted = CollectionView.LayoutString('painted'); - this.layoutDoc.layout_fieldKey = 'layout_painted'; - this.layoutDoc.type_collection = CollectionViewType.Freeform; - this.DocumentView?.().setToggleDetail(); - this.dataDoc.paintFunc = ComputedField.MakeFunction(`toJavascriptString(this['${this.fieldKey}']?.Text)`); - }, - icon: !this.Document._layout_enableAltContentUI ? 'eye-slash' : 'eye', - }); !Doc.noviceMode && optionItems.push({ description: `${this.Document._layout_autoHeight ? 'Lock' : 'Auto'} Height`, @@ -1411,9 +1423,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent); - } - destroy() { - setTimeout(() => { - try { - this.root.unmount(); - } catch {} - }); - } - deselectNode() { - this.dom.classList.remove('ProseMirror-selectednode'); - } - selectNode() { - this.dom.classList.add('ProseMirror-selectednode'); - } -} - -interface IPaintButtonViewInternal { - tbox: FormattedTextBox; - width: number; - height: number; - node: any; - getPos: any; -} - -@observer -export class PaintButtonViewInternal extends ObservableReactComponent { - _reactionDisposer: IReactionDisposer | undefined; - _textBoxDoc: Doc; - - constructor(props: IPaintButtonViewInternal) { - super(props); - makeObservable(this); - this._textBoxDoc = this._props.tbox.Document; - } - - return100 = () => 100; - @computed get _checked() { - return this._props.tbox.Document.onClick ? true : false; - } - - onCheckClick = () => { - const textView = this._props.tbox.DocumentView?.(); - if (textView) { - const paintedField = 'layout_' + this._props.tbox.fieldKey + 'Painted'; - const layoutFieldKey = StrCast(textView.layoutDoc.layout_fieldKey, 'layout'); - if (textView.layoutDoc.onClick) { - textView.layoutDoc[paintedField] = undefined; - textView.layoutDoc.onClick = undefined; - } else { - textView.layoutDoc.type_collection = CollectionViewType.Freeform; - textView.dataDoc[paintedField] = CollectionView.LayoutString(this._props.tbox.fieldKey); - textView.layoutDoc.layout_fieldKey = paintedField; - textView.setToggleDetail(layoutFieldKey.replace('layout_', '').replace('layout', '')); - textView.layoutDoc.layout_fieldKey = layoutFieldKey; - } - } - }; - - render() { - return ( -
- this.onCheckClick()} /> -
- ); - } -} diff --git a/src/client/views/nodes/formattedText/RichTextRules.ts b/src/client/views/nodes/formattedText/RichTextRules.ts index 8f7bc5282..ce2c33fb4 100644 --- a/src/client/views/nodes/formattedText/RichTextRules.ts +++ b/src/client/views/nodes/formattedText/RichTextRules.ts @@ -68,40 +68,21 @@ export class RichTextRules { ), // ``` create code block - textblockTypeInputRule(/^```$/, schema.nodes.code_block), - new InputRule( - new RegExp(/(^|\n)\^@paint/), // for code blocks '^' means the beginning of the block, not the line, so need to test for \n - (state, match, start, end) => { - const { dataDoc, layoutDoc, fieldKey } = this.TextBox; - layoutDoc.type_collection = CollectionViewType.Freeform; - const paintedField = 'layout_' + this.TextBox.fieldKey + 'Painted'; - dataDoc[paintedField] = CollectionView.LayoutString(this.TextBox.fieldKey); - const layoutFieldKey = StrCast(layoutDoc.layout_fieldKey); - layoutDoc.layout_fieldKey = paintedField; - this.TextBox.DocumentView?.().setToggleDetail(layoutFieldKey.replace('layout_', '').replace('layout', '')); - layoutDoc.layout_fieldKey = layoutFieldKey; - const comment = '/* enable as paint function '; - const endComment = ' */\n'; - const inCode = state.tr.selection.$anchor.node().type === schema.nodes.code_block; - if (inCode) { - const tr = state.tr - .deleteRange(start, end) - .insertText(comment) - .insert(start + comment.length, schema.nodes.paintButton.create()) - .insertText(endComment); - return tr.setSelection(new TextSelection(tr.doc.resolve(start + comment.length + endComment.length + 1))); - } else { - const tr = state.tr - .deleteRange(start, end) - .insertText(comment) - .insert(start + comment.length, schema.nodes.paintButton.create()) - .insertText(endComment) - .insert(start + comment.length + endComment.length + 1, schema.nodes.code_block.create()); - return tr.setSelection(new TextSelection(tr.doc.resolve(start + comment.length + endComment.length + 3))); - } - }, - { inCode: true } - ), + new InputRule(/^```$/, (state, match, start, end) => { + let $start = state.doc.resolve(start); + if (!$start.node(-1).canReplaceWith($start.index(-1), $start.indexAfter(-1), schema.nodes.code_block)) return null; + + // this enables text with code blocks to be used as a 'paint' function via a styleprovider button that is added to Docs that have an onPaint script + this.TextBox.layoutDoc.type_collection = CollectionViewType.Freeform; // make it a freeform when rendered as a collection since those are the only views that know about the paint function + const paintedField = 'layout_' + this.TextBox.fieldKey + 'Painted'; // make a layout field key for storing the CollectionView jsx string pointing to the textbox's text + this.TextBox.dataDoc[paintedField] = CollectionView.LayoutString(this.TextBox.fieldKey); + const layoutFieldKey = StrCast(this.TextBox.layoutDoc.layout_fieldKey); // save the current layout fieldkey + this.TextBox.layoutDoc.layout_fieldKey = paintedField; // setup the paint layout field key + this.TextBox.DocumentView?.().setToggleDetail(layoutFieldKey.replace('layout_', '').replace('layout', ''), 'onPaint'); // create the script to toggle between the painted and regular view + this.TextBox.layoutDoc.layout_fieldKey = layoutFieldKey; // restore the layout field key to text + + return state.tr.delete(start, end).setBlockType(start, start, schema.nodes.code_block); + }), // % set the font size new InputRule(new RegExp(/%([0-9]+)\s$/), (state, match, start, end) => { diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index 30e3aa5f0..f3fc51671 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -572,6 +572,16 @@ export namespace Doc { return false; } + export function RemoveEmbedding(doc: Doc, embedding: Doc) { + Doc.RemoveDocFromList(doc[DocData], 'proto_embeddings', embedding); + } + export function AddEmbedding(doc: Doc, embedding: Doc) { + Doc.AddDocToList(doc[DocData], 'proto_embeddings', embedding, undefined, undefined, undefined, undefined, undefined, true); + } + export function GetEmbeddings(doc: Doc) { + return DocListCast(Doc.Get(doc[DocData], 'proto_embeddings', true)); + } + export function MakeEmbedding(doc: Doc, id?: string) { const embedding = (!GetT(doc, 'isDataDoc', 'boolean', true) && doc.proto) || doc.type === DocumentType.CONFIG ? Doc.MakeCopy(doc, undefined, id) : Doc.MakeDelegate(doc, id); const layout = Doc.LayoutField(embedding); @@ -579,20 +589,18 @@ export namespace Doc { Doc.SetLayout(embedding, Doc.MakeEmbedding(layout)); } embedding.createdFrom = doc; - embedding.proto_embeddingId = doc[DocData].proto_embeddingId = DocListCast(doc[DocData].proto_embeddings).length - 1; + embedding.proto_embeddingId = doc[DocData].proto_embeddingId = Doc.GetEmbeddings(doc).length - 1; !Doc.GetT(embedding, 'title', 'string', true) && (embedding.title = ComputedField.MakeFunction(`renameEmbedding(this)`)); embedding.author = Doc.CurrentUserEmail; - Doc.AddDocToList(doc[DocData], 'proto_embeddings', embedding); - return embedding; } export function BestEmbedding(doc: Doc) { const dataDoc = doc[DocData]; - const availableEmbeddings = DocListCast(dataDoc.proto_embeddings); + const availableEmbeddings = Doc.GetEmbeddings(dataDoc); const bestEmbedding = [...(dataDoc !== doc ? [doc] : []), ...availableEmbeddings].find(doc => !doc.embedContainer && doc.author === Doc.CurrentUserEmail); - bestEmbedding && Doc.AddDocToList(dataDoc, 'protoEmbeddings', doc); + bestEmbedding && Doc.AddDocToList(dataDoc, 'protoEmbeddings', doc, undefined, undefined, undefined, undefined, undefined, true); return bestEmbedding ?? Doc.MakeEmbedding(doc); } @@ -951,7 +959,7 @@ export namespace Doc { Doc.GetProto(copy).embedContainer = undefined; Doc.GetProto(copy).proto_embeddings = new List([copy]); } else { - Doc.AddDocToList(copy[DocData], 'proto_embeddings', copy); + Doc.AddEmbedding(copy, copy); } copy.embedContainer = undefined; if (retitle) { @@ -972,9 +980,10 @@ export namespace Doc { Object.keys(doc) .filter(key => key.startsWith('acl')) .forEach(key => (delegate[key] = doc[key])); - if (!Doc.IsSystem(doc)) Doc.AddDocToList(doc[DocData], 'proto_embeddings', delegate); + if (!Doc.IsSystem(doc)) Doc.AddEmbedding(doc, delegate); title && (delegate.title = title); delegate[Initializing] = false; + Doc.AddEmbedding(doc, delegate); return delegate; } return undefined; @@ -995,7 +1004,7 @@ export namespace Doc { delegate[Initializing] = true; delegate.proto = delegateProto; delegate.author = Doc.CurrentUserEmail; - Doc.AddDocToList(delegateProto[DocData], 'proto_embeddings', delegate); + Doc.AddEmbedding(delegateProto, delegate); delegate[Initializing] = false; delegateProto[Initializing] = false; return delegate; -- cgit v1.2.3-70-g09d2