From 705975eb43e7904c62e7e847478f6d0dac60d443 Mon Sep 17 00:00:00 2001 From: bobzel Date: Sun, 23 Mar 2025 18:14:31 -0400 Subject: more _props.Document to .Document refactoring. type updates to prosemirrortransfer --- src/client/views/collections/CollectionTreeView.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'src/client/views/collections/CollectionTreeView.tsx') diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index e93724dd4..b7f49ac20 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -241,7 +241,7 @@ export class CollectionTreeView extends CollectionSubView { + onKey = (e: React.KeyboardEvent /* , textBox: FormattedTextBox */) => { if (this.outlineMode && e.key === 'Enter') { e.stopPropagation(); this.makeTextCollection(this.treeChildren); @@ -252,7 +252,6 @@ export class CollectionTreeView extends CollectionSubView {!(this.Document instanceof Doc) || !this.treeChildren ? null : this.Document.treeView_HasOverlay ? ( Date: Sun, 23 Mar 2025 20:51:21 -0400 Subject: fixed more typing errors. fixed updateBullets to not generate error when part of selection is not on a list. --- .../views/collections/CollectionNoteTakingView.tsx | 4 +- .../views/collections/CollectionStackingView.tsx | 4 +- .../views/collections/CollectionTreeView.tsx | 2 +- src/client/views/collections/TreeView.tsx | 4 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 12 ++--- src/client/views/nodes/FieldView.tsx | 2 +- .../formattedText/ProsemirrorExampleTransfer.ts | 58 ++++++++++++---------- src/client/views/nodes/formattedText/nodes_rts.ts | 5 +- 8 files changed, 48 insertions(+), 43 deletions(-) (limited to 'src/client/views/collections/CollectionTreeView.tsx') diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx index 2dabd3269..01695dbaf 100644 --- a/src/client/views/collections/CollectionNoteTakingView.tsx +++ b/src/client/views/collections/CollectionNoteTakingView.tsx @@ -271,7 +271,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { containerViewPath={this.childContainerViewPath} fitWidth={this._props.childLayoutFitWidth} isContentActive={emptyFunction} - onKey={this.onKeyDown} + onKey={this.onKey} // TODO: change this from a prop to a parameter passed into a function dontHideOnDrag isDocumentActive={this.isContentActive} @@ -438,7 +438,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { }; @undoBatch - onKeyDown = (e: React.KeyboardEvent, textBox: FormattedTextBox) => { + onKey = (e: KeyboardEvent, textBox: FormattedTextBox) => { if ((e.ctrlKey || textBox.Document._createDocOnCR) && ['Enter'].includes(e.key)) { e.stopPropagation?.(); const newDoc = Doc.MakeCopy(textBox.Document, true); diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 883b0bbe3..fd48a9dc1 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -310,7 +310,7 @@ export class CollectionStackingView extends CollectionSubView { + onKey = (e: KeyboardEvent, textBox: FormattedTextBox) => { if (['Enter'].includes(e.key) && e.ctrlKey) { e.stopPropagation?.(); const layoutFieldKey = StrCast(textBox.fieldKey); @@ -359,7 +359,7 @@ export class CollectionStackingView extends CollectionSubView { + onKey = (e: KeyboardEvent /* , textBox: FormattedTextBox */) => { if (this.outlineMode && e.key === 'Enter') { e.stopPropagation(); this.makeTextCollection(this.treeChildren); diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index 5ac283d22..cb7da8c84 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -939,7 +939,7 @@ export class TreeView extends ObservableReactComponent { if (property.startsWith(StyleProp.Decorations)) return null; return this._props?.treeView?._props.styleProvider?.(doc, props, property); // properties are inherited from the CollectionTreeView, not the hierarchical parent in the treeView }; - onKeyDown = (e: React.KeyboardEvent) => { + onKey = (e: KeyboardEvent) => { if (this.Document.treeView_HideHeader || (this.Document.treeView_HideHeaderIfTemplate && this.treeView._props.childLayoutTemplate?.()) || this.treeView.outlineMode) { switch (e.key) { case 'Tab': @@ -1138,7 +1138,7 @@ export class TreeView extends ObservableReactComponent { ScreenToLocalTransform={this.docTransform} renderDepth={this._props.renderDepth + 1} onClickScript={this.onChildClick} - onKey={this.onKeyDown} + onKey={this.onKey} containerViewPath={this.treeView.childContainerViewPath} childFilters={returnEmptyFilter} childFiltersByRanges={returnEmptyFilter} diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 25cec9c0d..7fd5d71fd 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1498,7 +1498,7 @@ export class CollectionFreeFormView extends CollectionSubView { + onKey = (e: KeyboardEvent, textBox: FormattedTextBox) => { if ((e.metaKey || e.ctrlKey || e.altKey || textBox.Document._createDocOnCR) && ['Tab', 'Enter'].includes(e.key)) { e.stopPropagation?.(); return this.createTextDocCopy(textBox, !e.altKey && e.key !== 'Tab'); @@ -1541,7 +1541,7 @@ export class CollectionFreeFormView extends CollectionSubView disposer?.()); } - updateIcon = (usePanelDimensions?: boolean) => { + updateIcon = (/*usePanelDimensions?: boolean*/) => { const contentDiv = this._mainCont; return !contentDiv ? new Promise(res => res()) : UpdateIcon( this.layoutDoc[Id] + '_icon_' + new Date().getTime(), contentDiv, - usePanelDimensions || true ? this._props.PanelWidth() : NumCast(this.layoutDoc._width), - usePanelDimensions || true ? this._props.PanelHeight() : NumCast(this.layoutDoc._height), + this._props.PanelWidth(), // usePanelDimensions ? this._props.PanelWidth() : NumCast(this.layoutDoc._width), + this._props.PanelHeight(), // usePanelDimensions ? this._props.PanelHeight() : NumCast(this.layoutDoc._height), this._props.PanelWidth(), this._props.PanelHeight(), 0, @@ -2314,7 +2314,7 @@ export class CollectionFreeFormView extends CollectionSubView ScriptField; onPointerDownScript?: () => ScriptField; onPointerUpScript?: () => ScriptField; - onKey?: (e: React.KeyboardEvent, textBox: FormattedTextBox) => boolean | undefined; + onKey?: (e: KeyboardEvent, textBox: FormattedTextBox) => boolean | undefined; fitWidth?: (doc: Doc) => boolean | undefined; dontCenter?: 'x' | 'y' | 'xy' | undefined; searchFilterDocs: () => Doc[]; diff --git a/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts b/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts index a75efd77b..eabc6455f 100644 --- a/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts +++ b/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts @@ -1,12 +1,12 @@ import { chainCommands, deleteSelection, exitCode, joinBackward, joinDown, joinUp, lift, newlineInCode, selectNodeBackward, setBlockType, splitBlockKeepMarks, toggleMark, wrapIn } from 'prosemirror-commands'; import { redo, undo } from 'prosemirror-history'; -import { MarkType, Node, ResolvedPos, Schema } from 'prosemirror-model'; +import { MarkType, Node, Schema } from 'prosemirror-model'; import { liftListItem, sinkListItem, splitListItem, wrapInList } from 'prosemirror-schema-list'; import { Command, EditorState, NodeSelection, TextSelection, Transaction } from 'prosemirror-state'; import { liftTarget } from 'prosemirror-transform'; import { EditorView } from 'prosemirror-view'; import { ClientUtils } from '../../../../ClientUtils'; -import { Utils } from '../../../../Utils'; +import { numberRange, Utils } from '../../../../Utils'; import { AclAdmin, AclAugment, AclEdit, DocData } from '../../../../fields/DocSymbols'; import { GetEffectiveAcl } from '../../../../fields/util'; import { Docs } from '../../../documents/Documents'; @@ -19,12 +19,12 @@ const mac = typeof navigator !== 'undefined' ? /Mac/.test(navigator.platform) : export type KeyMap = { [key: string]: Command }; -export const updateBullets = (tx2: Transaction, schema: Schema, assignedMapStyle?: string, from?: number, to?: number) => { +export function updateBullets(tx2: Transaction, schema: Schema, assignedMapStyle?: string, from?: number, to?: number) { let mapStyle = assignedMapStyle; tx2.doc.descendants((node: Node, offset: number /* , index: any */) => { if ((from === undefined || to === undefined || (from <= offset + node.nodeSize && to >= offset)) && (node.type === schema.nodes.ordered_list || node.type === schema.nodes.list_item)) { - const { path } = tx2.doc.resolve(offset) as unknown as { path: (number | Node)[] }; // bcz: can't access path .. need to FIX - let depth = Array.from(path).reduce((p: number, c: number | Node) => p + ((c as Node).type === schema.nodes.ordered_list ? 1 : 0), 0); + const resolved = tx2.doc.resolve(offset); + let depth = [0, ...numberRange(resolved.depth)].reduce((p, c, idx) => p + (resolved.node(idx).type === schema.nodes.ordered_list ? 1 : 0), 0); if (node.type === schema.nodes.ordered_list) { if (depth === 0 && !assignedMapStyle) mapStyle = node.attrs.mapStyle; depth++; @@ -33,7 +33,7 @@ export const updateBullets = (tx2: Transaction, schema: Schema, assignedMapStyle } }); return tx2; -}; +} export function buildKeymap>(schema: S, tbox?: FormattedTextBox): KeyMap { const keys: { [key: string]: Command } = {}; @@ -43,8 +43,9 @@ export function buildKeymap>(schema: S, tbox?: Formatte } function onKey(): boolean | undefined { - // bcz: this is pretty hacky -- prosemirror doesn't send us the keyboard event, but the 'event' variable is in scope.. so we access it anyway - return tbox?._props.onKey?.(event, tbox); + // bcz: hack -- prosemirror doesn't send us the keyboard event, but the 'event' variable is in scope.. so we access it anyway + // eslint-disable-next-line no-restricted-globals + return event && tbox?._props.onKey?.(event as unknown as KeyboardEvent, tbox); } const canEdit = (state: EditorState) => { @@ -53,8 +54,9 @@ export function buildKeymap>(schema: S, tbox?: Formatte switch (permissions) { case AclAugment: { - const prevNode = (state.selection as any).$cursor.nodeBefore; - const prevUser = !prevNode ? ClientUtils.CurrentUserEmail() : prevNode.marks.lastElement()?.attrs.userid; + // previously used hack: (state.selection as any).$cursor.nodeBefore; + const prevNode = state.selection?.$anchor.nodeBefore; + const prevUser = !prevNode ? ClientUtils.CurrentUserEmail() : Array.from(prevNode.marks).lastElement()?.attrs.userid; if (prevUser !== ClientUtils.CurrentUserEmail()) { return false; } @@ -208,12 +210,14 @@ export function buildKeymap>(schema: S, tbox?: Formatte return true; }); bind('Cmd-]', (state: EditorState, dispatch: ((tx: Transaction) => void) | undefined) => { - const resolved = state.doc.resolve(state.selection.from) as ResolvedPos & { path: (Node | number)[] }; // bcz: this is bad. path is not publically visible - const { tr } = state; - if (resolved?.parent.type.name === 'paragraph') { - tr.setNodeMarkup(resolved.path[resolved.path.length - 4] as number, schema.nodes.paragraph, { ...resolved.parent.attrs, align: 'right' }, resolved.parent.marks); + const { + tr, + selection: { $from }, + } = state; + if ($from?.parent.type.name === 'paragraph') { + tr.setNodeMarkup(state.selection.from - state.selection.$from.parentOffset - 1, schema.nodes.paragraph, { ...$from.parent.attrs, align: 'right' }, $from.parent.marks); } else { - const node = resolved.nodeAfter; + const node = $from.nodeAfter; const sm = state.storedMarks || undefined; if (node) { tr.replaceRangeWith(state.selection.from, state.selection.from, schema.nodes.paragraph.create({ align: 'right' })).setStoredMarks([...node.marks, ...(sm || [])]); @@ -223,12 +227,14 @@ export function buildKeymap>(schema: S, tbox?: Formatte return true; }); bind('Cmd-\\', (state: EditorState, dispatch: ((tx: Transaction) => void) | undefined) => { - const resolved = state.doc.resolve(state.selection.from) as ResolvedPos & { path: (Node | number)[] }; // bcz: this is bad. path is not publically visible - const { tr } = state; - if (resolved?.parent.type.name === 'paragraph') { - tr.setNodeMarkup(resolved.path[resolved.path.length - 4] as number, schema.nodes.paragraph, { ...resolved.parent.attrs, align: 'center' }, resolved.parent.marks); + const { + tr, + selection: { $from }, + } = state; + if ($from?.parent.type.name === 'paragraph') { + tr.setNodeMarkup(state.selection.from - state.selection.$from.parentOffset - 1, schema.nodes.paragraph, { ...$from.parent.attrs, align: 'center' }, $from.parent.marks); } else { - const node = resolved.nodeAfter; + const node = $from.nodeAfter; const sm = state.storedMarks || undefined; if (node) { tr.replaceRangeWith(state.selection.from, state.selection.from, schema.nodes.paragraph.create({ align: 'center' })).setStoredMarks([...node.marks, ...(sm || [])]); @@ -238,12 +244,14 @@ export function buildKeymap>(schema: S, tbox?: Formatte return true; }); bind('Cmd-[', (state: EditorState, dispatch: ((tx: Transaction) => void) | undefined) => { - const resolved = state.doc.resolve(state.selection.from) as ResolvedPos & { path: (Node | number)[] }; // bcz: this is bad. path is not publically visible - const { tr } = state; - if (resolved?.parent.type.name === 'paragraph') { - tr.setNodeMarkup(resolved.path[resolved.path.length - 4] as number, schema.nodes.paragraph, { ...resolved.parent.attrs, align: 'left' }, resolved.parent.marks); + const { + tr, + selection: { $from }, + } = state; + if ($from?.parent.type.name === 'paragraph') { + tr.setNodeMarkup(state.selection.from - state.selection.$from.parentOffset - 1, schema.nodes.paragraph, { ...$from.parent.attrs, align: 'left' }, $from.parent.marks); } else { - const node = resolved.nodeAfter; + const node = $from.nodeAfter; const sm = state.storedMarks || undefined; if (node) { tr.replaceRangeWith(state.selection.from, state.selection.from, schema.nodes.paragraph.create({ align: 'left' })).setStoredMarks([...node.marks, ...(sm || [])]); diff --git a/src/client/views/nodes/formattedText/nodes_rts.ts b/src/client/views/nodes/formattedText/nodes_rts.ts index 02ded3103..fe7b77e74 100644 --- a/src/client/views/nodes/formattedText/nodes_rts.ts +++ b/src/client/views/nodes/formattedText/nodes_rts.ts @@ -385,10 +385,6 @@ export const nodes: { [index: string]: NodeSpec } = { }; }, }, - { - style: 'list-style-type=disc', - getAttrs: () => ({ mapStyle: 'bullet' }), - }, { tag: 'ol', getAttrs: dom => { @@ -443,6 +439,7 @@ export const nodes: { [index: string]: NodeSpec } = { mapStyle: { default: 'decimal' }, // "decimal", "multi", "bullet" visibility: { default: true }, }, + marks: '_', content: '(paragraph|audiotag)+ | ((paragraph|audiotag)+ ordered_list)', parseDOM: [ { -- cgit v1.2.3-70-g09d2 From a3eab5f2b8eca6ff7a21ea9d043b90c953c35f03 Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 26 Mar 2025 16:36:15 -0400 Subject: fix so that views use don't use the rootDocument, but rather the current rendering document. got rid of resolvedDataDoc -- just use rootDocument[DocData] --- src/client/views/DocComponent.tsx | 44 +++++++++++----------- src/client/views/DocumentDecorations.tsx | 2 +- .../views/collections/CollectionCarouselView.tsx | 3 +- .../CollectionStackingViewFieldColumn.tsx | 5 ++- src/client/views/collections/CollectionSubView.tsx | 12 +++--- .../views/collections/CollectionTreeView.tsx | 2 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 2 +- .../collectionGrid/CollectionGridView.tsx | 5 ++- .../CollectionMulticolumnView.tsx | 5 ++- .../CollectionMultirowView.tsx | 5 ++- .../views/nodes/CollectionFreeFormDocumentView.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 2 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 2 +- src/fields/Doc.ts | 19 +++++----- 14 files changed, 58 insertions(+), 52 deletions(-) (limited to 'src/client/views/collections/CollectionTreeView.tsx') diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index 3a868d1f9..e3d47317c 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -36,7 +36,7 @@ export function DocComponent

() { * NOTE: it is very unlikely that you really want to use this method. Instead * consider: Document, layoutDoc, dataDoc */ - get _renderDoc() { + get Document() { return this._props.Document; } @@ -46,8 +46,8 @@ export function DocComponent

() { * necessarily the Doc being rendered in the current React component. * This Doc inherits from the dataDoc, and may or may not inherit (or be) the layoutDoc. */ - get Document() { - return DocCast(this._renderDoc.rootDocument, this._renderDoc); + get rootDoc() { + return DocCast(this.Document.rootDocument, this.Document); } /** * This is the document being rendered by the React component. In the @@ -56,14 +56,14 @@ export function DocComponent

() { * This may or may not inherit from the data doc. */ @computed get layoutDoc() { - return this._props.LayoutTemplateString ? this._renderDoc : Doc.Layout(this._renderDoc, this._props.LayoutTemplate?.()); + return this._props.LayoutTemplateString ? this.Document : Doc.Layout(this.Document, this._props.LayoutTemplate?.()); } /** * This is the unique data repository for a document that stores the intrinsic document data. */ @computed get dataDoc() { - return this._renderDoc[DocData]; + return this.Document[DocData]; } } return Component; @@ -92,10 +92,8 @@ export function ViewBoxBaseComponent

() { * This is the doc that is being rendered. It will be either: * 1) the same as Document if the root of a regular or compound Doc is rendered * 2) the same as the layoutDoc if a component of a compound Doc is rendered. - * NOTE: it is very unlikely that you really want to use this method. Instead - * consider: Document, layoutDoc, dataDoc */ - get _renderDoc() { + get Document() { return this._props.Document; } @@ -104,9 +102,12 @@ export function ViewBoxBaseComponent

() { * this is the outermost Doc that represents the entire compound Doc. It is not * necessarily the Doc being rendered in the current React component. * This Doc inherits from the dataDoc, and may or may not inherit (or be) the layoutDoc. + * + * NOTE: it is very unlikely that you really want to use this method. Instead + * consider: Document, layoutDoc, dataDoc */ - get Document() { - return DocCast(this._renderDoc.rootDocument, this._renderDoc); + get rootDoc() { + return DocCast(this.Document.rootDocument, this.Document); } /** * This is the document being rendered by the React component. In the @@ -115,14 +116,14 @@ export function ViewBoxBaseComponent

() { * This may or may not inherit from the data doc. */ @computed get layoutDoc() { - return Doc.Layout(this._renderDoc); + return Doc.Layout(this.Document); } /** * This is the unique data repository for a dcoument that stores the intrinsic document data */ @computed get dataDoc() { - return this._renderDoc.isTemplateForField || this._renderDoc.isTemplateDoc ? (this._props.TemplateDataDocument ?? this._renderDoc[DocData]) : this._renderDoc[DocData]; + return this.Document.isTemplateForField || this.Document.isTemplateDoc ? (this._props.TemplateDataDocument ?? this.Document[DocData]) : this.Document[DocData]; } /** @@ -165,10 +166,8 @@ export function ViewBoxAnnotatableComponent

() { * This is the doc that is being rendered. It will be either: * 1) the same as Document if the root of a regular or compound Doc is rendered * 2) the same as the layoutDoc if a component of a compound Doc is rendered. - * NOTE: it would unlikely that you really want to use this instead of the - * other Doc options (Document, layoutDoc, dataDoc) */ - get _renderDoc() { + get Document() { return this._props.Document; } @@ -177,24 +176,27 @@ export function ViewBoxAnnotatableComponent

() { * this is the outermost Doc that represents the entire compound Doc. It is not * necessarily the Doc being rendered in the current React component. * This Doc inherits from the dataDoc, and may or may not inherit (or be) the layoutDoc. + * + * NOTE: it would unlikely that you really want to use this instead of the + * other Doc options (Document, layoutDoc, dataDoc) */ - @computed get Document() { - return DocCast(this._renderDoc.rootDocument, this._renderDoc); + @computed get rootDoc() { + return DocCast(this.Document.rootDocument, this.Document); } /** * This is the document being rendered. It may be a template so it may or may no inherit from the data doc. */ @computed get layoutDoc() { - return Doc.Layout(this._renderDoc); + return Doc.Layout(this.Document); } /** * This is the unique data repository for a dcoument that stores the intrinsic document data */ @computed get dataDoc() { - return this._renderDoc.isTemplateForField || this._renderDoc.isTemplateDoc ? - (this._props.TemplateDataDocument ?? this._renderDoc[DocData]) : - this._props.Document[DocData]; // prettier-ignore + return this.Document.isTemplateForField || this.Document.isTemplateDoc ? + (this._props.TemplateDataDocument ?? this.Document[DocData]) : + this.Document[DocData]; // prettier-ignore } /** diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 19b987cb5..92b4d6fbf 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -635,7 +635,7 @@ export class DocumentDecorations extends ObservableReactComponent { const created = Docs.Create.CarouselDocument([], { _width: 400, _height: 200, title: fieldKey }); if (created) { - const container = this._props.Doc.resolvedDataDoc ? Doc.GetProto(this._props.Doc) : this._props.Doc; + const container = DocCast(this._props.Doc.rootDocument)?.[DocData] ? Doc.GetProto(this._props.Doc) : this._props.Doc; if (container.isTemplateDoc) { Doc.MakeMetadataFieldTemplate(created, container); return Doc.AddDocToList(container, Doc.LayoutFieldKey(container), created); diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index e34ba93a9..cfd52f9ee 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -108,11 +108,11 @@ export function CollectionSubView() { } get dataDoc() { - return this._props.TemplateDataDocument instanceof Doc && this._renderDoc.isTemplateForField // + return this._props.TemplateDataDocument instanceof Doc && this.Document.isTemplateForField // ? Doc.GetProto(this._props.TemplateDataDocument) - : this.Document.resolvedDataDoc - ? this._renderDoc - : this.Document[DocData]; // if the layout document has a resolvedDataDoc, then we don't want to get its parent which would be the unexpanded template + : this.Document.rootDocument + ? this.Document + : this.Document[DocData]; // if the layout document has a rootDocument, then we don't want to get its parent which would be the unexpanded template } get childContainerViewPath() { @@ -133,7 +133,7 @@ export function CollectionSubView() { @computed get childLayoutPairs(): { layout: Doc; data: Doc }[] { const { TemplateDataDocument } = this._props; const validPairs = this.childDocs - .map(doc => Doc.GetLayoutDataDocPair(this._renderDoc, !this._props.isAnnotationOverlay ? TemplateDataDocument : undefined, doc)) + .map(doc => Doc.GetLayoutDataDocPair(this.Document, !this._props.isAnnotationOverlay ? TemplateDataDocument : undefined, doc)) .filter( pair => // filter out any documents that have a proto that we don't have permissions to @@ -299,7 +299,7 @@ export function CollectionSubView() { const dragData = de.complete.docDragData; if (dragData) { const sourceDragAction = dragData.dropAction; - const sameCollection = !dragData.draggedDocuments.some(d => d.embedContainer !== this._renderDoc); + const sameCollection = !dragData.draggedDocuments.some(d => d.embedContainer !== this.Document); dragData.dropAction = !sameCollection // if doc from another tree ? sourceDragAction || targetDropAction // then use the source's dragAction otherwise the target's : sourceDragAction === dropActionType.inPlace // if source drag is inPlace diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 1960e12bd..418c437d5 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -187,7 +187,7 @@ export class CollectionTreeView extends CollectionSubView, before?: boolean): boolean => { const addDocRelativeTo = (adocs: Doc | Doc[]) => (adocs as Doc[]).reduce((flg, doc) => flg && Doc.AddDocToList(this.Document[DocData], this._props.fieldKey, doc, relativeTo, before), true); - if (this.Document.resolvedDataDoc instanceof Promise) return false; + if (this.Document.rootDocument instanceof Promise) return false; const doclist = toList(docs); const res = relativeTo === undefined ? this._props.addDocument?.(doclist) || false : addDocRelativeTo(doclist); res && diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 09a1b0c53..09d43c5b0 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -286,7 +286,7 @@ export class CollectionFreeFormView extends CollectionSubView this.fitContentBounds?.cx ?? NumCast(this.Document[this.panXFieldKey], NumCast(this.Document.freeform_panX, 1)); panY = () => this.fitContentBounds?.cy ?? NumCast(this.Document[this.panYFieldKey], NumCast(this.Document.freeform_panY, 1)); - zoomScaling = () => this.fitContentBounds?.scale ?? NumCast(Doc.Layout(this.Document)[this.scaleFieldKey], 1); // , NumCast(DocCast(this.Document.resolvedDataDoc)?.[this.scaleFieldKey], 1)); + zoomScaling = () => this.fitContentBounds?.scale ?? NumCast(Doc.Layout(this.Document)[this.scaleFieldKey], 1); // , NumCast(DocCast(this.Document.rootDocument)?.[this.scaleFieldKey], 1)); PanZoomCenterXf = () => (this._props.isAnnotationOverlay && this.zoomScaling() === 1 ? `` : `translate(${this.centeringShiftX}px, ${this.centeringShiftY}px) scale(${this.zoomScaling()}) translate(${-this.panX()}px, ${-this.panY()}px)`); ScreenToContentsXf = () => this.screenToFreeformContentsXf.copy(); getActiveDocuments = () => this.childLayoutPairs.filter(pair => this.isCurrent(pair.layout)).map(pair => pair.layout); diff --git a/src/client/views/collections/collectionGrid/CollectionGridView.tsx b/src/client/views/collections/collectionGrid/CollectionGridView.tsx index e7f1de7f1..8393c719b 100644 --- a/src/client/views/collections/collectionGrid/CollectionGridView.tsx +++ b/src/client/views/collections/collectionGrid/CollectionGridView.tsx @@ -4,7 +4,7 @@ import * as React from 'react'; import { returnFalse, returnZero, setupMoveUpEvents } from '../../../../ClientUtils'; import { Doc, Opt } from '../../../../fields/Doc'; import { Id } from '../../../../fields/FieldSymbols'; -import { BoolCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types'; +import { BoolCast, DocCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types'; import { emptyFunction } from '../../../../Utils'; import { Docs } from '../../../documents/Documents'; import { DragManager } from '../../../util/DragManager'; @@ -16,6 +16,7 @@ import { DocumentView } from '../../nodes/DocumentView'; import { CollectionSubView, SubCollectionViewProps } from '../CollectionSubView'; import './CollectionGridView.scss'; import Grid, { Layout } from './Grid'; +import { DocData } from '../../../../fields/DocSymbols'; @observer export class CollectionGridView extends CollectionSubView() { @@ -192,7 +193,7 @@ export class CollectionGridView extends CollectionSubView() { val.lower)).omit} // prettier-ignore - Document={this._renderDoc} + Document={this.Document} renderDepth={this._props.renderDepth} isContentActive={this._props.isContentActive} childFilters={this._props.childFilters} diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 3268ba0f7..4ea2c66f3 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -758,7 +758,7 @@ export class DocumentViewInternal extends DocComponent )?.length) { dataDoc[templateField] = ObjectField.MakeCopy(templateLayoutDoc[templateField] as List); @@ -912,9 +911,9 @@ export namespace Doc { console.log('Warning: GetLayoutDataDocPair childDoc not defined'); return { layout: childDoc, data: childDoc }; } - const resolvedDataDoc = Doc.AreProtosEqual(containerDataDoc, containerDoc) || (!Doc.isTemplateDoc(childDoc) && !Doc.isTemplateForField(childDoc)) ? undefined : containerDataDoc; + const data = Doc.AreProtosEqual(containerDataDoc, containerDoc) || (!Doc.isTemplateDoc(childDoc) && !Doc.isTemplateForField(childDoc)) ? undefined : containerDataDoc; const templateRoot = DocCast(containerDoc?.rootDocument); - return { layout: Doc.expandTemplateLayout(childDoc, templateRoot), data: resolvedDataDoc }; + return { layout: Doc.expandTemplateLayout(childDoc, templateRoot), data }; } export function FindReferences(infield: Doc | List, references: Set, system: boolean | undefined) { @@ -1083,7 +1082,7 @@ export namespace Doc { export function ApplyTemplateTo(templateDoc: Doc, target: Doc, targetKey: string, titleTarget: string | undefined) { if (!Doc.AreProtosEqual(target[targetKey] as Doc, templateDoc)) { - if (target.resolvedDataDoc) { + if (target.rootDocument) { target[targetKey] = new PrefetchProxy(templateDoc); } else { titleTarget && (Doc.GetProto(target).title = titleTarget); @@ -1301,7 +1300,7 @@ export namespace Doc { highlightedDocs.add(doc); doc[Highlight] = true; doc[Animation] = presentationEffect; - if (dataAndDisplayDocs && !doc.resolvedDataDoc) { + if (dataAndDisplayDocs && !doc.rootDocument) { // if doc is a layout template then we don't want to highlight the proto since that will be the entire template, not just the specific layout field highlightedDocs.add(doc[DocData]); doc[DocData][Highlight] = true; @@ -1331,7 +1330,7 @@ export namespace Doc { : Cast(doc.dragFactory, Doc, null)?.isTemplateDoc ? doc.dragFactory : Cast(Doc.Layout(doc), Doc, null)?.isTemplateDoc - ? Cast(Doc.Layout(doc), Doc, null).resolvedDataDoc + ? Cast(Doc.Layout(doc), Doc, null).rootDocument ? Doc.Layout(doc).proto : Doc.Layout(doc) : undefined; -- cgit v1.2.3-70-g09d2 From b0bb28202fa77556768d1da93bf9ea879c6ba2e5 Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 10 Apr 2025 12:05:55 -0400 Subject: performance fixes for text boxes to not call screenToLocal unnecessarily. simplifications to template data docs --- src/client/views/DocumentDecorations.scss | 2 +- src/client/views/DocumentDecorations.tsx | 2 +- src/client/views/StyleProvider.tsx | 24 +++-- src/client/views/TagsView.scss | 3 + .../views/collections/CollectionCarouselView.scss | 2 + .../views/collections/CollectionCarouselView.tsx | 14 ++- .../views/collections/CollectionNoteTakingView.tsx | 6 +- .../views/collections/CollectionStackingView.tsx | 13 ++- src/client/views/collections/CollectionSubView.tsx | 7 +- .../views/collections/CollectionTreeView.tsx | 14 +-- .../collectionGrid/CollectionGridView.tsx | 11 +-- .../CollectionMulticolumnView.tsx | 106 ++++++++++----------- .../CollectionMultirowView.tsx | 106 ++++++++++----------- src/client/views/nodes/DocumentView.scss | 6 ++ src/client/views/nodes/DocumentView.tsx | 87 ++++++++++------- src/client/views/nodes/FieldView.tsx | 2 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 16 ++-- .../formattedText/ProsemirrorExampleTransfer.ts | 3 +- src/client/views/nodes/trails/PresElementBox.tsx | 2 +- 19 files changed, 229 insertions(+), 197 deletions(-) (limited to 'src/client/views/collections/CollectionTreeView.tsx') diff --git a/src/client/views/DocumentDecorations.scss b/src/client/views/DocumentDecorations.scss index 28cebe23c..09a13634f 100644 --- a/src/client/views/DocumentDecorations.scss +++ b/src/client/views/DocumentDecorations.scss @@ -40,10 +40,10 @@ $resizeHandler: 8px; } .documentDecorations-tagsView { position: absolute; - height: 100%; width: 100%; pointer-events: all; border-radius: 50%; + top: 30; // offset by height of documentButtonBar so that items can be clicked without overlap interference color: black; } } diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 452dd60ee..0756d3d9e 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -863,7 +863,7 @@ export class DocumentDecorations extends ObservableReactComponent 1 || !seldocview.showTags ? 'none' : undefined, transform: `translate(${-this._resizeBorderWidth + 10}px, ${2 * this._resizeBorderWidth + bounds.b - bounds.y + this._titleHeight}px) `, }}> {DocumentView.Selected().length > 1 ? : null} diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx index a3067907d..e8876f96f 100644 --- a/src/client/views/StyleProvider.tsx +++ b/src/client/views/StyleProvider.tsx @@ -327,7 +327,7 @@ export function DefaultStyleProvider(doc: Opt, props: Opt, props: Opt doc?.pointerEvents !== 'none' ? null : ( + const showLock = doc?.pointerEvents === 'none' + const lock = () => !showLock ? null : (

toggleLockedPosition(doc)}>
); - const paint = () => !doc?.onPaint ? null : ( + const showPaint = doc?.onPaint; + const paint = () => !showPaint ? null : (
togglePaintView(e, doc, props)}>
); + const showFilterIcon = + StrListCast(doc?._childFilters).length || StrListCast(doc?._childFiltersByRanges).length + ? 'green' // #18c718bd' //'hasFilter' + : childFilters?.().filter(f => ClientUtils.IsRecursiveFilter(f) && f !== ClientUtils.noDragDocsFilter).length || childFiltersByRanges?.().length + ? 'orange' // 'inheritsFilter' + : undefined; + const showFilter = showFilterIcon && !hideFilterStatus; const filter = () => { const dashView = untracked(() => DocumentView.getDocumentView(Doc.ActiveDashboard)); - const showFilterIcon = - StrListCast(doc?._childFilters).length || StrListCast(doc?._childFiltersByRanges).length - ? 'green' // #18c718bd' //'hasFilter' - : childFilters?.().filter(f => ClientUtils.IsRecursiveFilter(f) && f !== ClientUtils.noDragDocsFilter).length || childFiltersByRanges?.().length - ? 'orange' // 'inheritsFilter' - : undefined; - return !showFilterIcon || hideFilterStatus ? null : ( + return !showFilter ? null : (
, props: Opt {paint()} {lock()} diff --git a/src/client/views/TagsView.scss b/src/client/views/TagsView.scss index d58b55ab5..a940502d4 100644 --- a/src/client/views/TagsView.scss +++ b/src/client/views/TagsView.scss @@ -16,6 +16,9 @@ min-height: unset !important; } } + .tagsView-editing-box { + pointer-events: all; + } } } diff --git a/src/client/views/collections/CollectionCarouselView.scss b/src/client/views/collections/CollectionCarouselView.scss index 1080aa703..962b590c8 100644 --- a/src/client/views/collections/CollectionCarouselView.scss +++ b/src/client/views/collections/CollectionCarouselView.scss @@ -9,6 +9,8 @@ height: 50; display: inline-block; width: 100%; + bottom: 0; + position: absolute; } .collectionCarouselView-image { height: calc(100% - 50px); diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx index c80ac23eb..2d3f8cb0e 100644 --- a/src/client/views/collections/CollectionCarouselView.tsx +++ b/src/client/views/collections/CollectionCarouselView.tsx @@ -16,7 +16,6 @@ import { FocusViewOptions } from '../nodes/FocusViewOptions'; import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox'; import './CollectionCarouselView.scss'; import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView'; -import { DocData } from '../../../fields/DocSymbols'; @observer export class CollectionCarouselView extends CollectionSubView() { @@ -116,12 +115,14 @@ export class CollectionCarouselView extends CollectionSubView() { ? false : undefined; // prettier-ignore onPassiveWheel = (e: WheelEvent) => e.stopPropagation(); + renderDoc = (doc: Doc, showCaptions: boolean, overlayFunc?: (r: DocumentView | null) => void) => { return ( diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx index 01695dbaf..173147f64 100644 --- a/src/client/views/collections/CollectionNoteTakingView.tsx +++ b/src/client/views/collections/CollectionNoteTakingView.tsx @@ -258,11 +258,9 @@ export class CollectionNoteTakingView extends CollectionSubView() { const noteTakingDocTransform = () => this.getDocTransform(doc, dref); return ( { - dref = r || undefined; - }} + ref={r => (dref = r || undefined)} Document={doc} - TemplateDataDocument={dataDoc ?? (!Doc.AreProtosEqual(doc[DocData], doc) ? doc[DocData] : undefined)} + TemplateDataDocument={doc.isTemplateDoc || doc.isTemplateForField ? this._props.TemplateDataDocument : undefined} pointerEvents={this.blockPointerEventsWhenDragging} renderDepth={this._props.renderDepth + 1} PanelWidth={width} diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index d7cf0ffc2..4f60acb18 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -675,12 +675,12 @@ export class CollectionStackingView extends CollectionSubView 35; + @computed get menuBtnDoc() { return DocCast(this.layoutDoc.layout_headerButton); } // prettier-ignore @computed get buttonMenu() { - const menuDoc = DocCast(this.layoutDoc.layout_headerButton); - return !menuDoc ? null : ( -
+ return !this.menuBtnDoc ? null : ( +
- {buttonMenu || noviceExplainer ? ( + {this.menuBtnDoc || noviceExplainer ? (
- {buttonMenu ? this.buttonMenu : null} + {this.menuBtnDoc ? this.buttonMenu : null} {Doc.noviceMode && noviceExplainer ?
{StrCast(noviceExplainer)}
: null}
) : null} diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index a88707c6f..375c0fe53 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -603,7 +603,12 @@ export function CollectionSubView() { */ @computed get uiBtnScaling() { return this.maxWidgetSize / this._sideBtnWidth; } // prettier-ignore - screenXPadding = () => (this.uiBtnScaling * this._sideBtnWidth - NumCast(this.layoutDoc.xMargin)) / this._props.ScreenToLocalTransform().Scale; + screenXPadding = (docView?: DocumentView) => { + if (!docView) return 0; + const diff = this._props.PanelWidth() - docView.PanelWidth(); + const xpad1 = this.uiBtnScaling * (this._sideBtnWidth - NumCast(this.layoutDoc.xMargin)) - diff / 2; // this._sideBtnWidth; + return xpad1 / (docView.NativeDimScaling?.() || 1); + }; filteredChildDocs = () => this.childLayoutPairs.map(pair => pair.layout); childDocsFunc = () => this.childDocs; @action setFilterFunc = (func?: (doc: Doc) => boolean) => { this._filterFunc = func; }; // prettier-ignore diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 418c437d5..962fbdcd7 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -8,7 +8,7 @@ import { DocData } from '../../../fields/DocSymbols'; import { Id } from '../../../fields/FieldSymbols'; import { listSpec } from '../../../fields/Schema'; import { ScriptField } from '../../../fields/ScriptField'; -import { BoolCast, Cast, NumCast, ScriptCast, StrCast, toList } from '../../../fields/Types'; +import { BoolCast, Cast, DocCast, NumCast, ScriptCast, StrCast, toList } from '../../../fields/Types'; import { TraceMobx } from '../../../fields/util'; import { emptyFunction, Utils } from '../../../Utils'; import { Docs } from '../../documents/Documents'; @@ -200,7 +200,7 @@ export class CollectionTreeView extends CollectionSubView { // need to test if propagation has stopped because GoldenLayout forces a parallel react hierarchy to be created for its top-level layout const layoutItems: ContextMenuProps[] = []; - const menuDoc = ScriptCast(Cast(this.layoutDoc.layout_headerButton, Doc, null)?.onClick)?.script.originalScript === CollectionTreeView.AddTreeFunc; + const menuDoc = ScriptCast(this.menuBtnDoc?.onClick)?.script.originalScript === CollectionTreeView.AddTreeFunc; menuDoc && layoutItems.push({ description: 'Create new folder', event: () => CollectionTreeView.addTreeFolder(this.Document), icon: 'paint-brush' }); if (!Doc.noviceMode) { layoutItems.push({ @@ -347,14 +347,14 @@ export class CollectionTreeView extends CollectionSubView 35; + @computed get menuBtnDoc() { return DocCast(this.layoutDoc.layout_headerButton); } // prettier-ignore @computed get buttonMenu() { - const menuDoc = Cast(this.layoutDoc.layout_headerButton, Doc, null); // To create a multibutton menu add a CollectionLinearView - return !menuDoc ? null : ( -
+ return !this.menuBtnDoc ? null : ( +
(this._props.isDocumentActive?.() && (this._props.childDocumentsActive?.() || BoolCast(this.Document.childDocumentsActive)) ? true : undefined); /** * - * @param layout + * @param childLayout * @param dxf the x- and y-translations of the decorations box as a transform i.e. this.lookupIndividualTransform * @param width * @param height * @returns the `ContentFittingDocumentView` of the node */ - getDisplayDoc = (layout: Doc, dxf: () => Transform, width: () => number, height: () => number) => ( + getDisplayDoc = (childLayout: Doc, dxf: () => Transform, width: () => number, height: () => number) => ( { - if (this.columnUnitLength === undefined) { - return Transform.Identity(); // we're still waiting on promises to resolve - } - let offset = 0; - for (const { layout: candidate } of this.childLayoutPairs) { - if (candidate === layout) { - return this.ScreenToLocalBoxXf().translate(-offset / (this._props.NativeDimScaling?.() || 1), 0); + if (this.columnUnitLength !== undefined) { + let offset = 0; + for (const { layout: candidate } of this.childLayoutPairs) { + if (candidate === layout) { + return this.ScreenToLocalBoxXf().translate(-offset / (this._props.NativeDimScaling?.() || 1), 0); + } + offset += this.lookupPixels(candidate) + resizerWidth; } - offset += this.lookupPixels(candidate) + resizerWidth; } return Transform.Identity(); }; @@ -262,50 +261,51 @@ export class CollectionMulticolumnView extends CollectionSubView() { ? true : undefined; }; - getDisplayDoc = (childLayout: Doc) => { - const width = () => this.lookupPixels(childLayout); - const height = () => this._props.PanelHeight() - 2 * NumCast(this.layoutDoc._yMargin) - (BoolCast(this.layoutDoc.showWidthLabels) ? 20 : 0); - const dxf = () => - this.lookupIndividualTransform(childLayout) + childHeight = () => this._props.PanelHeight() - 2 * NumCast(this.layoutDoc._yMargin) - (BoolCast(this.layoutDoc.showWidthLabels) ? 20 : 0); + childWidth = computedFn((childDoc: Doc) => () => this.lookupPixels(childDoc)); + childXf = computedFn( + (childDoc: Doc) => () => + this.lookupIndividualTransform(childDoc) .translate(-NumCast(this.layoutDoc._xMargin), -NumCast(this.layoutDoc._yMargin)) - .scale(this._props.NativeDimScaling?.() || 1); - return ( - - ); - }; + .scale(this._props.NativeDimScaling?.() || 1) + ); + getDisplayDoc = (childLayout: Doc) => ( + + ); + /** * @returns the resolved list of rendered child documents, displayed * at their resolved pixel widths, each separated by a resizer. diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx index f95928cf6..6bbe55f54 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx @@ -2,7 +2,7 @@ import { action, computed, makeObservable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { Doc, DocListCast } from '../../../../fields/Doc'; -import { BoolCast, DocCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types'; +import { BoolCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types'; import { DragManager } from '../../../util/DragManager'; import { dropActionType } from '../../../util/DropActionTypes'; import { Transform } from '../../../util/Transform'; @@ -11,7 +11,7 @@ import { CollectionSubView, SubCollectionViewProps } from '../CollectionSubView' import './CollectionMultirowView.scss'; import HeightLabel from './MultirowHeightLabel'; import ResizeBar from './MultirowResizer'; -import { DocData } from '../../../../fields/DocSymbols'; +import { computedFn } from 'mobx-utils'; interface HeightSpecifier { magnitude: number; @@ -179,16 +179,14 @@ export class CollectionMultirowView extends CollectionSubView() { * documents before the target. */ private lookupIndividualTransform = (layout: Doc) => { - if (this.rowUnitLength === undefined) { - return Transform.Identity(); // we're still waiting on promises to resolve - } - let offset = 0; - // eslint-disable-next-line no-restricted-syntax - for (const { layout: candidate } of this.childLayoutPairs) { - if (candidate === layout) { - return this.ScreenToLocalBoxXf().translate(0, -offset / (this._props.NativeDimScaling?.() || 1)); + if (this.rowUnitLength !== undefined) { + let offset = 0; + for (const { layout: candidate } of this.childLayoutPairs) { + if (candidate === layout) { + return this.ScreenToLocalBoxXf().translate(0, -offset / (this._props.NativeDimScaling?.() || 1)); + } + offset += this.lookupPixels(candidate) + resizerHeight; } - offset += this.lookupPixels(candidate) + resizerHeight; } return Transform.Identity(); // type coersion, this case should never be hit }; @@ -244,49 +242,51 @@ export class CollectionMultirowView extends CollectionSubView() { ? true : undefined; }; - getDisplayDoc = (layout: Doc) => { - const height = () => this.lookupPixels(layout); - const width = () => this._props.PanelWidth() - 2 * NumCast(this.layoutDoc._xMargin) - (BoolCast(this.layoutDoc.showWidthLabels) ? 20 : 0); - const dxf = () => - this.lookupIndividualTransform(layout) + childHeight = computedFn((childDoc: Doc) => () => this.lookupPixels(childDoc)); + childWidth = () => this._props.PanelWidth() - 2 * NumCast(this.layoutDoc._xMargin) - (BoolCast(this.layoutDoc.showWidthLabels) ? 20 : 0); + childXf = computedFn( + (childDoc: Doc) => () => + this.lookupIndividualTransform(childDoc) .translate(-NumCast(this.layoutDoc._xMargin), -NumCast(this.layoutDoc._yMargin)) - .scale(this._props.NativeDimScaling?.() || 1); - return ( - - ); - }; + .scale(this._props.NativeDimScaling?.() || 1) + ); + + getDisplayDoc = (childLayout: Doc) => ( + + ); + /** * @returns the resolved list of rendered child documents, displayed * at their resolved pixel widths, each separated by a resizer. diff --git a/src/client/views/nodes/DocumentView.scss b/src/client/views/nodes/DocumentView.scss index f60f33608..5ac66f2cd 100644 --- a/src/client/views/nodes/DocumentView.scss +++ b/src/client/views/nodes/DocumentView.scss @@ -277,6 +277,12 @@ bottom: 0; pointer-events: none; } +.documentView-widgetDecorations { + transform-origin: top right; + position: absolute; + top: 0; + right: 0; +} .documentView-editorView-history { position: absolute; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index b03dd3944..bec5ea5c1 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -712,6 +712,54 @@ export class DocumentViewInternal extends DocComponent (this.aiContentsHeight() * (this._props.NativeWidth?.() || 1)) / (this._props.NativeHeight?.() || 1); aiContentsHeight = () => Math.max(10, this._props.PanelHeight() - this._aiWinHeight * this.uiBtnScaling); + aiEditor = () => ( + <> +
this.historyRef(this._oldAiWheel, (this._oldAiWheel = r))} + style={{ + transform: `scale(${this.uiBtnScaling})`, + height: this.aiContentsHeight() / this.uiBtnScaling, + width: ((this._props.PanelWidth() - this.aiContentsWidth()) * 0.95) / this.uiBtnScaling, + }}> + {this._componentView?.componentAIViewHistory?.() ?? null} +
+
this.historyRef(this._oldHistoryWheel, (this._oldHistoryWheel = r))}> +
+ {this._componentView?.componentAIView?.() ?? null} + {this._props.DocumentView?.() ? : null} +
+ + ); + @computed get tagsOverlay() { + return ( +
+ {this._props.DocumentView?.() && !this._props.docViewPath().slice(-2)[0].ComponentView?.isUnstyledView?.() ? : null} +
+ ); + } + tagsOverlayFunc = () => (this._props.DocumentView?.().showTags ? this.tagsOverlay : null); + @computed get widgetOverlay() { + return ( +
+ {this.widgetDecorations} +
+ ); + } + widgetOverlayFunc = () => (this.widgetDecorations ? this.widgetOverlay : null); @computed get viewBoxContents() { TraceMobx(); const isInk = this.layoutDoc._layout_isSvg && !this._props.LayoutTemplateString; @@ -742,43 +790,8 @@ export class DocumentViewInternal extends DocComponent
- {!this._props.showAIEditor ? ( -
- {this._props.DocumentView?.() && !this._props.docViewPath().slice(-2)[0].ComponentView?.isUnstyledView?.() ? : null} -
- ) : ( - <> -
this.historyRef(this._oldAiWheel, (this._oldAiWheel = r))} - style={{ - transform: `scale(${this.uiBtnScaling})`, - height: this.aiContentsHeight() / this.uiBtnScaling, - width: ((this._props.PanelWidth() - this.aiContentsWidth()) * 0.95) / this.uiBtnScaling, - }}> - {this._componentView?.componentAIViewHistory?.() ?? null} -
-
this.historyRef(this._oldHistoryWheel, (this._oldHistoryWheel = r))}> -
- {this._componentView?.componentAIView?.() ?? null} - {this._props.DocumentView?.() ? : null} -
- - )} -
{this.widgetDecorations ?? null}
+ {this._props.showAIEditor ? this.aiEditor() : this.tagsOverlayFunc()} + {this.widgetOverlayFunc()} ); } diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index 74059bd12..ad6d93d43 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -50,7 +50,7 @@ export interface FieldViewSharedProps { TemplateDataDocument?: Doc; renderDepth: number; scriptContext?: unknown; // can be assigned anything and will be passed as 'scriptContext' to any OnClick script that executes on this document - screenXPadding?: () => number; // padding in screen space coordinates (used by text box to reflow around UI buttons in carouselView) + screenXPadding?: (view: DocumentView | undefined) => number; // padding in screen space coordinates (used by text box to reflow around UI buttons in carouselView) xPadding?: number; yPadding?: number; dontRegisterView?: boolean; diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 6fced76bd..a45b8a488 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -215,7 +215,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { - const rootDoc: Doc = Doc.isTemplateDoc(this._props.docViewPath().lastElement()?.Document) ? this.Document : DocCast(this.Document.rootDocument, this.Document); + const rootDoc = Doc.isTemplateDoc(this._props.docViewPath().lastElement()?.Document) ? this.Document : this.rootDoc; if (!pinProps && this.EditorView?.state.selection.empty) return rootDoc; const anchor = Docs.Create.ConfigDocument({ title: StrCast(rootDoc.title), annotationOn: rootDoc }); this.addDocument(anchor); @@ -308,7 +308,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { if (node.type === this.EditorView?.state.schema.nodes.dashField) { - const refDoc = !node.attrs.docId ? DocCast(this.Document.rootDocument, this.Document) : (DocServer.GetCachedRefField(node.attrs.docId as string) as Doc); + const refDoc = !node.attrs.docId ? this.rootDoc : (DocServer.GetCachedRefField(node.attrs.docId as string) as Doc); const fieldKey = StrCast(node.attrs.fieldKey); return ( (node.attrs.hideKey ? '' : fieldKey + ':') + // @@ -316,7 +316,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent !this._props.isContentActive() && FormattedTextBoxComment.textBox === this && FormattedTextBoxComment.Hide); - const scrSize = (which: number, view = this._props.docViewPath().slice(-which)[0]) => - [view?._props.PanelWidth() /(view?.screenToLocalScale()??1), view?._props.PanelHeight() / (view?.screenToLocalScale()??1)]; // prettier-ignore - const scrMargin = [Math.max(0, (scrSize(2)[0] - scrSize(1)[0]) / 2), Math.max(0, (scrSize(2)[1] - scrSize(1)[1]) / 2)]; - const paddingX = Math.max(NumCast(this.layoutDoc._xMargin), this._props.xPadding ?? 0, 0, ((this._props.screenXPadding?.() ?? 0) - scrMargin[0]) * this.ScreenToLocalBoxXf().Scale); - const paddingY = Math.max(NumCast(this.layoutDoc._yMargin), 0, ((this._props.yPadding ?? 0) - scrMargin[1]) * this.ScreenToLocalBoxXf().Scale); + const paddingX = Math.max(NumCast(this.layoutDoc._xMargin), 0, this._props.xPadding ?? 0, this._props.screenXPadding?.(this._props.DocumentView?.()) ?? 0); + const paddingY = Math.max(NumCast(this.layoutDoc._yMargin), 0, this._props.yPadding ?? 0); // prettier-ignore const styleFromLayout = styleFromLayoutString(this.Document, this._props, scale); // this converts any expressions in the format string to style props. e.g., return this.isLabel ? ( diff --git a/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts b/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts index eabc6455f..7ae1fc202 100644 --- a/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts +++ b/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts @@ -50,8 +50,7 @@ export function buildKeymap>(schema: S, tbox?: Formatte const canEdit = (state: EditorState) => { if (!tbox) return true; - const permissions = GetEffectiveAcl(tbox._props.TemplateDataDocument ?? tbox.Document[DocData]); - switch (permissions) { + switch (GetEffectiveAcl(tbox.dataDoc)) { case AclAugment: { // previously used hack: (state.selection as any).$cursor.nodeBefore; diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx index 31cd1603f..7e0375275 100644 --- a/src/client/views/nodes/trails/PresElementBox.tsx +++ b/src/client/views/nodes/trails/PresElementBox.tsx @@ -67,7 +67,7 @@ export class PresElementBox extends ViewBoxBaseComponent() { // Since this node is being rendered with a template, this method retrieves // the actual slide being rendered from the auto-generated rendering template @computed get slideDoc() { - return DocCast(this.Document.rootDocument, this.Document); + return this.rootDoc; } // this is the document in the workspaces that is targeted by the slide -- cgit v1.2.3-70-g09d2 From eef391dba5ee9f1588274f8719eb4047fe844e22 Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 10 Apr 2025 23:08:13 -0400 Subject: changed naming of makeDelegates to not add a number at the end. switched dataNote to MetaNote and cleaned up initialization of it. fixed sidebar/stacking view to not grab wheel evebnts when not active. fixed dashfieldview to vcenter labels. fixed height and scrolling of templae menu. simplified formattedtextbox menu --- src/client/documents/DocUtils.ts | 2 +- src/client/documents/Documents.ts | 5 +- src/client/util/CurrentUserUtils.ts | 83 +++++++++++----------- src/client/views/DocumentButtonBar.tsx | 2 +- src/client/views/SidebarAnnos.tsx | 3 +- src/client/views/TemplateMenu.scss | 4 ++ .../views/collections/CollectionStackingView.tsx | 2 +- .../views/collections/CollectionTreeView.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 70 +++++++++--------- .../views/nodes/formattedText/DashFieldView.scss | 1 + .../views/nodes/formattedText/FormattedTextBox.tsx | 61 ---------------- .../views/nodes/formattedText/RichTextRules.ts | 2 +- src/fields/Doc.ts | 6 +- 13 files changed, 96 insertions(+), 147 deletions(-) (limited to 'src/client/views/collections/CollectionTreeView.tsx') diff --git a/src/client/documents/DocUtils.ts b/src/client/documents/DocUtils.ts index f5eee84aa..0d15a91e9 100644 --- a/src/client/documents/DocUtils.ts +++ b/src/client/documents/DocUtils.ts @@ -899,7 +899,7 @@ export namespace DocUtils { const ndoc = Doc.MakeDelegateWithProto(dragFactory); if (ndoc && dragFactory.dragFactory_count !== undefined) { dragFactory.dragFactory_count = NumCast(dragFactory.dragFactory_count) + 1; - Doc.GetProto(ndoc).title = ndoc.title + ' ' + NumCast(dragFactory.dragFactory_count).toString(); + Doc.GetProto(ndoc).title = ndoc.title; } return ndoc; } diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 0e3c614fe..d93a432d4 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -221,7 +221,6 @@ export class DocumentOptions { color?: STRt = new StrInfo('foreground color data doc', false); hidden?: BOOLt = new BoolInfo('whether the document is not rendered by its collection', false); backgroundColor?: STRt = new StrInfo('background color for data doc', false); - _override_backgroundColor?: BOOLt = new BoolInfo("whether the layout template overrides the data doc's background color"); opacity?: NUMt = new NumInfo('document opacity', false); viewTransitionTime?: NUMt = new NumInfo('transition duration for view parameters', false); dontRegisterView?: BOOLt = new BoolInfo('are views of this document registered so that they can be found when following links, etc', false); @@ -284,7 +283,7 @@ export class DocumentOptions { _layout_curPage?: NUMt = new NumInfo('current page of a PDF or other? paginated document', false); _layout_currentTimecode?: NUMt = new NumInfo('the current timecode of a time-based document (e.g., current time of a video) value is in seconds', false); _layout_fitWidth?: BOOLt = new BoolInfo('whether document should scale its contents to fit its rendered width or not (e.g., for PDFviews)'); - _layout_fieldKey?: STRt = new StrInfo('the field key containing the current layout definition', false); + layout_fieldKey?: STRt = new StrInfo('the field key containing the current layout definition', false); _layout_enableAltContentUI?: BOOLt = new BoolInfo('whether to show alternate content button'); _layout_flashcardType?: STRt = new StrInfo('flashcard style to render in ComparisonBox. currently just "flashcard".'); _layout_showTitle?: string; // field name to display in header (:hover is an optional suffix) @@ -678,7 +677,7 @@ export namespace Docs { // whatever options pertain to this specific prototype const options: DocumentOptions = { isSystem: true, - _layout_fieldKey: 'layout', + layout_fieldKey: 'layout', title, type, isBaseProto: true, diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 4c492cae0..1c0f11c91 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -144,14 +144,16 @@ export class CurrentUserUtils { static setupNoteTemplates(doc: Doc, field="template_notes") { const tempNotes = DocCast(doc[field]); const reqdTempOpts:DocumentOptions[] = [ - { title: "Postit", _override_backgroundColor: true, backgroundColor: "yellow", icon: "sticky-note", _layout_showTitle: "title", layout_borderRounding: "5px"}, - { title: "Idea", _override_backgroundColor: true, backgroundColor: "pink", icon: "lightbulb" , _layout_showTitle: "title"}, - { title: "Topic", _override_backgroundColor: true, backgroundColor: "lightblue", icon: "book-open" , _layout_showTitle: "title"}]; + { title: "Postit", backgroundColor: "yellow", icon: "sticky-note", _layout_showTitle: "title", layout_borderRounding: "5px"}, + { title: "Idea", backgroundColor: "pink", icon: "lightbulb" , _layout_showTitle: "title"}, + { title: "Topic", backgroundColor: "lightblue", icon: "book-open" , _layout_showTitle: "title"}]; + + const reqdNoteList = [...reqdTempOpts.map(opts => { const reqdOpts = {...opts, isSystem:true, width:200, layout_autoHeight: true, layout_fitWidth: true}; const noteTemp = tempNotes ? DocListCast(tempNotes.data).find(fdoc => fdoc.title === opts.title): undefined; return DocUtils.AssignOpts(noteTemp, reqdOpts) ?? MakeTemplate(Docs.Create.TextDocument("",reqdOpts)); - }), ... DocListCast(tempNotes?.data).filter(note => !reqdTempOpts.find(reqd => reqd.title === note.title))]; + }), DocCast(doc.emptyMetaNote), ... DocListCast(tempNotes?.data).filter(note => !reqdTempOpts.find(reqd => reqd.title === note.title))]; const reqdOpts:DocumentOptions = { title: "Note Layouts", _height: 75, isSystem: true }; return DocUtils.AssignOpts(tempNotes, reqdOpts, reqdNoteList) ?? (doc[field] = Docs.Create.TreeDocument(reqdNoteList, reqdOpts)); @@ -247,7 +249,6 @@ export class CurrentUserUtils { title: string, toolTip: string, icon: string, ignoreClick?: boolean, dragFactory?: Doc, backgroundColor?: string, openFactoryAsDelegate?:boolean, openFactoryLocation?:string, clickFactory?: Doc, scripts?: { onClick?: string, onDragStart?: string}, funcs?: {onDragStart?:string, hidden?: string}, }[] { - const standardOps = (key:string) => ({ title : "Untitled "+ key, _layout_fitWidth: false, isSystem: true, "dragFactory_count": 0, cloneFieldFilter: new List(["isSystem"]) }); const json = { doc: { type: "doc", @@ -272,17 +273,17 @@ export class CurrentUserUtils { // " " + // " " + // "
"; - const headerBtnHgt = 10; - const headerTemplate = (opts:DocumentOptions) => - MakeTemplate(Docs.Create.RTFDocument(new RichTextField(JSON.stringify(json), ""), { ...opts, title: "Header Template", + const metadataBtnHght = 10; + const metaNoteTemplate = (opts:DocumentOptions) => + MakeTemplate(Docs.Create.RTFDocument(new RichTextField(JSON.stringify(json), ""), { ...opts, title: "MetaNote", layout:` - + - Metadata + Metadata ` - }, "header")); + }, "metaNote")); const slideView = (opts:DocumentOptions) => MakeTemplate(Docs.Create.MultirowDocument( [ @@ -405,9 +406,9 @@ pie title Minerals in my tap water {key: "Script", creator: opts => Docs.Create.ScriptingDocument(null, opts), opts: { _width: 200, _height: 250, }}, {key: "DataViz", creator: opts => Docs.Create.DataVizDocument("", opts), opts: { _width: 300, _height: 300, }}, // AARAV ADD // - {key: "DailyJournal",creator:opts => Docs.Create.DailyJournalDocument("", opts),opts:{ _width: 300, _height: 300}}, + {key: "DailyJournal",creator:opts => Docs.Create.DailyJournalDocument("", opts),opts: { _width: 300, _height: 300}}, {key: "Chat", creator: Docs.Create.ChatDocument, opts: { _width: 500, _height: 500, _layout_fitWidth: true, }}, - {key: "Header", creator: headerTemplate, opts: { _width: 300, _height: 120, _header_pointerEvents: "all", _header_height: 50, _header_fontSize: 9,_layout_autoHeightMargins: 50, _layout_autoHeight: true, treeView_HideUnrendered: true}}, + {key: "MetaNote", creator: metaNoteTemplate, opts: { _width: 300, _height: 120, _header_pointerEvents: "all", _header_height: 50, _header_fontSize: 9,_layout_autoHeightMargins: 50, _layout_autoHeight: true, treeView_HideUnrendered: true}}, {key: "ViewSlide", creator: slideView, opts: { _width: 400, _height: 300, _xMargin: 3, _yMargin: 3,}}, {key: "Trail", creator: Docs.Create.PresDocument, opts: { _width: 400, _height: 30, _type_collection: CollectionViewType.Stacking, _layout_dontCenter:'xy', dropAction: dropActionType.embed, treeView_HideTitle: true, _layout_fitWidth:true, layout_boxShadow: "0 0" }}, {key: "Tab", creator: opts => Docs.Create.FreeformDocument([], opts), opts: { _width: 500, _height: 800, _layout_fitWidth: true, _freeform_backgroundGrid: true, }}, @@ -420,40 +421,42 @@ pie title Minerals in my tap water {key: "Plotly", creator: plotlyView, opts: { _width: 300, _height: 300, }}, ]; + const standardOps = (key:string) => ({ title : "Untitled "+ key, _layout_fitWidth: false, isSystem: true, "dragFactory_count": 0, cloneFieldFilter: new List(["isSystem"]) }); emptyThings.forEach( thing => DocUtils.AssignDocField(doc, "empty"+thing.key, (opts) => thing.creator(opts), {...standardOps(thing.key), ...thing.opts}, undefined, thing.scripts, thing.funcs)); - + DocCast(Doc.UserDoc().emptyMetaNote).title = "MetaNote"; // hack: metanotes are used a template, so 'untitled metaNote' is an awkward name + return [ - { toolTip: "Tap or drag to create a note", title: "Note", icon: "sticky-note", dragFactory: doc.emptyNote as Doc, clickFactory: DocCast(doc.emptyNote)}, - { toolTip: "Tap or drag to create a flashcard", title: "Flashcard", icon: "id-card", dragFactory: doc.emptyFlashcard as Doc, clickFactory: DocCast(doc.emptyFlashcard)}, - { toolTip: "Tap or drag to create an equation", title: "Math", icon: "calculator", dragFactory: doc.emptyEquation as Doc, clickFactory: DocCast(doc.emptyEquation)}, - { toolTip: "Tap or drag to create a mermaid node", title: "Mermaids", icon: "rocket", dragFactory: doc.emptyMermaids as Doc, clickFactory: DocCast(doc.emptyMermaids)}, - { toolTip: "Tap or drag to create a plotly node", title: "Plotly", icon: "rocket", dragFactory: doc.emptyPlotly as Doc, clickFactory: DocCast(doc.emptyMermaids)}, - { toolTip: "Tap or drag to create a note board", title: "Notes", icon: "book", dragFactory: doc.emptyNoteboard as Doc, clickFactory: DocCast(doc.emptyNoteboard)}, - { toolTip: "Tap or drag to create an image", title: "Image", icon: "image", dragFactory: doc.emptyImage as Doc, clickFactory: DocCast(doc.emptyImage)}, - { toolTip: "Tap or drag to create a collection", title: "Col", icon: "folder", dragFactory: doc.emptyCollection as Doc, clickFactory: DocCast(doc.emptyTab)}, - { toolTip: "Tap or drag to create a webpage", title: "Web", icon: "globe-asia", dragFactory: doc.emptyWebpage as Doc, clickFactory: DocCast(doc.emptyWebpage)}, - { toolTip: "Tap or drag to create a comparison box", title: "Compare", icon: "columns", dragFactory: doc.emptyComparison as Doc, clickFactory: DocCast(doc.emptyComparison)}, - { toolTip: "Tap or drag to create a diagram", title: "Diagram", icon: "tree", dragFactory: doc.emptyDiagram as Doc, clickFactory: DocCast(doc.emptyDiagram)}, - { toolTip: "Tap or drag to create an audio recorder", title: "Audio", icon: "microphone", dragFactory: doc.emptyAudio as Doc, clickFactory: DocCast(doc.emptyAudio), openFactoryLocation: OpenWhere.overlay}, - { toolTip: "Tap or drag to create a map", title: "Map", icon: "map-marker-alt", dragFactory: doc.emptyMap as Doc, clickFactory: DocCast(doc.emptyMap)}, - { toolTip: "Tap or drag to create a chat assistant", title: "Assistant Chat", icon: "book",dragFactory: doc.emptyChat as Doc, clickFactory: DocCast(doc.emptyChat)}, - { toolTip: "Tap or drag to create a screen grabber", title: "Grab", icon: "photo-video", dragFactory: doc.emptyScreengrab as Doc, clickFactory: DocCast(doc.emptyScreengrab), openFactoryLocation: OpenWhere.overlay, funcs: { hidden: "IsNoviceMode()"}}, - { toolTip: "Tap or drag to create a WebCam recorder", title: "WebCam", icon: "photo-video", dragFactory: doc.emptyWebCam as Doc, clickFactory: DocCast(doc.emptyWebCam), openFactoryLocation: OpenWhere.overlay, funcs: { hidden: "IsNoviceMode()"}}, - { toolTip: "Tap or drag to create a button", title: "Button", icon: "circle", dragFactory: doc.emptyButton as Doc, clickFactory: DocCast(doc.emptyButton)}, - { toolTip: "Tap or drag to create a scripting box", title: "Script", icon: "terminal", dragFactory: doc.emptyScript as Doc, clickFactory: DocCast(doc.emptyScript), funcs: { hidden: "IsNoviceMode()"}}, - { toolTip: "Tap or drag to create a data viz node", title: "DataViz", icon: "chart-bar", dragFactory: doc.emptyDataViz as Doc, clickFactory: DocCast(doc.emptyDataViz)}, - { toolTip: "Tap or drag to create a journal entry", title: "Journal", icon: "book", dragFactory: doc.emptyDailyJournal as Doc,clickFactory:DocCast(doc.emptyDataJournal), }, - { toolTip: "Tap or drag to create a bullet slide", title: "PPT Slide", icon: "person-chalkboard", dragFactory: doc.emptySlide as Doc, clickFactory: DocCast(doc.emptySlide), openFactoryLocation: OpenWhere.overlay,funcs: { hidden: "IsNoviceMode()"}}, - { toolTip: "Tap or drag to create a view slide", title: "View Slide", icon: "address-card", dragFactory: doc.emptyViewSlide as Doc, clickFactory: DocCast(doc.emptyViewSlide), openFactoryLocation: OpenWhere.overlay,funcs: { hidden: "IsNoviceMode()"}}, - { toolTip: "Tap or drag to create a data note", title: "DataNote", icon: "window-maximize", dragFactory: doc.emptyHeader as Doc, clickFactory: DocCast(doc.emptyHeader), openFactoryAsDelegate: true, funcs: { hidden: "IsNoviceMode()"} }, - { toolTip: "Toggle a Calculator REPL", title: "replviewer", icon: "calculator", clickFactory: '' as unknown as Doc, openFactoryLocation: OpenWhere.overlay}, // hack: clickFactory is not a Doc but will get interpreted as a custom UI by the openDoc() onClick script + { toolTip: "Tap or drag to create a note", title: "Note", icon: "sticky-note", dragFactory: doc.emptyNote as Doc, clickFactory: DocCast(doc.emptyNote)}, + { toolTip: "Tap or drag to create a flashcard", title: "Flashcard", icon: "id-card", dragFactory: doc.emptyFlashcard as Doc, clickFactory: DocCast(doc.emptyFlashcard)}, + { toolTip: "Tap or drag to create an equation", title: "Math", icon: "calculator", dragFactory: doc.emptyEquation as Doc, clickFactory: DocCast(doc.emptyEquation)}, + { toolTip: "Tap or drag to create a mermaid node", title: "Mermaids", icon: "rocket", dragFactory: doc.emptyMermaids as Doc, clickFactory: DocCast(doc.emptyMermaids)}, + { toolTip: "Tap or drag to create a plotly node", title: "Plotly", icon: "rocket", dragFactory: doc.emptyPlotly as Doc, clickFactory: DocCast(doc.emptyMermaids)}, + { toolTip: "Tap or drag to create a note board", title: "Notes", icon: "book", dragFactory: doc.emptyNoteboard as Doc, clickFactory: DocCast(doc.emptyNoteboard)}, + { toolTip: "Tap or drag to create an image", title: "Image", icon: "image", dragFactory: doc.emptyImage as Doc, clickFactory: DocCast(doc.emptyImage)}, + { toolTip: "Tap or drag to create a collection", title: "Col", icon: "folder", dragFactory: doc.emptyCollection as Doc, clickFactory: DocCast(doc.emptyTab)}, + { toolTip: "Tap or drag to create a webpage", title: "Web", icon: "globe-asia", dragFactory: doc.emptyWebpage as Doc, clickFactory: DocCast(doc.emptyWebpage)}, + { toolTip: "Tap or drag to create a comparison box", title: "Compare", icon: "columns", dragFactory: doc.emptyComparison as Doc, clickFactory: DocCast(doc.emptyComparison)}, + { toolTip: "Tap or drag to create a diagram", title: "Diagram", icon: "tree", dragFactory: doc.emptyDiagram as Doc, clickFactory: DocCast(doc.emptyDiagram)}, + { toolTip: "Tap or drag to create an audio recorder", title: "Audio", icon: "microphone", dragFactory: doc.emptyAudio as Doc, clickFactory: DocCast(doc.emptyAudio), openFactoryLocation: OpenWhere.overlay}, + { toolTip: "Tap or drag to create a map", title: "Map", icon: "map-marker-alt", dragFactory: doc.emptyMap as Doc, clickFactory: DocCast(doc.emptyMap)}, + { toolTip: "Tap or drag to create a chat assistant", title: "Chat Assist", icon: "book", dragFactory: doc.emptyChat as Doc, clickFactory: DocCast(doc.emptyChat)}, + { toolTip: "Tap or drag to create a screen grabber", title: "Grab", icon: "photo-video", dragFactory: doc.emptyScreengrab as Doc, clickFactory: DocCast(doc.emptyScreengrab), openFactoryLocation: OpenWhere.overlay, funcs: { hidden: "IsNoviceMode()"}}, + { toolTip: "Tap or drag to create a WebCam recorder", title: "WebCam", icon: "photo-video", dragFactory: doc.emptyWebCam as Doc, clickFactory: DocCast(doc.emptyWebCam), openFactoryLocation: OpenWhere.overlay, funcs: { hidden: "IsNoviceMode()"}}, + { toolTip: "Tap or drag to create a button", title: "Button", icon: "circle", dragFactory: doc.emptyButton as Doc, clickFactory: DocCast(doc.emptyButton)}, + { toolTip: "Tap or drag to create a scripting box", title: "Script", icon: "terminal", dragFactory: doc.emptyScript as Doc, clickFactory: DocCast(doc.emptyScript), funcs: { hidden: "IsNoviceMode()"}}, + { toolTip: "Tap or drag to create a data viz node", title: "DataViz", icon: "chart-bar", dragFactory: doc.emptyDataViz as Doc, clickFactory: DocCast(doc.emptyDataViz)}, + { toolTip: "Tap or drag to create a journal entry", title: "Journal", icon: "book", dragFactory:doc.emptyDailyJournal as Doc,clickFactory: DocCast(doc.emptyDataJournal), }, + { toolTip: "Tap or drag to create a bullet slide", title: "PPT Slide", icon:"person-chalkboard",dragFactory: doc.emptySlide as Doc, clickFactory: DocCast(doc.emptySlide), openFactoryLocation: OpenWhere.overlay, funcs: { hidden: "IsNoviceMode()"}}, + { toolTip: "Tap or drag to create a view slide", title: "View Slide", icon: "address-card", dragFactory: doc.emptyViewSlide as Doc, clickFactory: DocCast(doc.emptyViewSlide), openFactoryLocation: OpenWhere.overlay, funcs: { hidden: "IsNoviceMode()"}}, + { toolTip: "Tap or drag to create a data note", title: "MetaNote", icon: "window-maximize", dragFactory: doc.emptyMetaNote as Doc, clickFactory: DocCast(doc.emptyMetaNote), openFactoryAsDelegate: true, funcs: { hidden: "IsNoviceMode()"} }, + { toolTip: "Toggle a Calculator REPL", title: "replviewer", icon: "calculator", clickFactory: '' as unknown as Doc, openFactoryLocation: OpenWhere.overlay}, // hack: clickFactory is not a Doc but will get interpreted as a custom UI by the openDoc() onClick script ].map(tuple => ( { openFactoryLocation: OpenWhere.addRight, scripts: { onClick: 'openDoc(copyDragFactory(this.clickFactory,this.openFactoryAsDelegate), this.openFactoryLocation)', onDragStart: '{ return copyDragFactory(this.dragFactory,this.openFactoryAsDelegate); }'}, funcs: tuple.funcs, - ...tuple, })) + ...tuple, })); } /// Initalizes the "creator" buttons for the sidebar-- eg. the default set of draggable document creation tools diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index 9a57a5e6c..6f2f051cd 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -512,7 +512,7 @@ export class DocumentButtonBar extends ObservableReactComponent<{ views: () => (
{this.pinButton}
{this.recordButton}
{this.calendarButton}
-
{this.aiEditorButton}
+ {this.view0?.HasAIEditor ?
{this.aiEditorButton}
: null}
{this.keywordButton}
{!Doc.UserDoc().documentLinksButton_fullMenu ? null :
{this.shareButton}
}
{this.menuButton}
diff --git a/src/client/views/SidebarAnnos.tsx b/src/client/views/SidebarAnnos.tsx index b7e6318b1..573c28ccf 100644 --- a/src/client/views/SidebarAnnos.tsx +++ b/src/client/views/SidebarAnnos.tsx @@ -1,7 +1,7 @@ import { computed, makeObservable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; -import { ClientUtils, returnAll, returnFalse, returnOne, returnZero } from '../../ClientUtils'; +import { ClientUtils, returnFalse, returnOne, returnZero } from '../../ClientUtils'; import { emptyFunction } from '../../Utils'; import { Doc, DocListCast, Field, FieldResult, FieldType, StrListCast } from '../../fields/Doc'; import { Id } from '../../fields/FieldSymbols'; @@ -253,7 +253,6 @@ export class SidebarAnnos extends ObservableReactComponent
diff --git a/src/client/views/TemplateMenu.scss b/src/client/views/TemplateMenu.scss index 8879fc20d..049945517 100644 --- a/src/client/views/TemplateMenu.scss +++ b/src/client/views/TemplateMenu.scss @@ -40,12 +40,16 @@ height: 100%; width: 100%; max-height: 250px; + overflow: auto; .templateToggle, .chromeToggle { text-align: left; color: black; } + .collectionTreeView { + height: fit-content !important; + } input { margin-right: 10px; diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 4f60acb18..112510265 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -720,7 +720,7 @@ export class CollectionStackingView extends CollectionSubView e.stopPropagation(); + onPassiveWheel = (e: WheelEvent) => this._props.isContentActive() && e.stopPropagation(); render() { TraceMobx(); const editableViewProps = { diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 962fbdcd7..3497a62cb 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -467,7 +467,7 @@ export class CollectionTreeView extends CollectionSubView +
{!(this.Document instanceof Doc) || !this.treeChildren ? null : this.Document.treeView_HasOverlay ? ( DocumentView.SetLightboxDoc(this.Document), icon: 'external-link-alt' }); } appearanceItems.push({ description: 'Pin', event: () => this._props.pinToPres(this.Document, {}), icon: 'map-pin' }); - appearanceItems.push({ description: 'AI view', event: () => this._docView?.toggleAIEditor(), icon: 'map-pin' }); + this._componentView?.componentAIView?.() && appearanceItems.push({ description: 'AI view', event: () => this._docView?.toggleAIEditor(), icon: 'map-pin' }); !Doc.noviceMode && templateDoc && appearanceItems.push({ description: 'Open Template ', event: () => this._props.addDocTab(templateDoc, OpenWhere.addRight), icon: 'eye' }); !appearance && appearanceItems.length && cm.addItem({ description: 'Appearance...', subitems: appearanceItems, icon: 'compass' }); @@ -660,7 +660,7 @@ export class DocumentViewInternal extends DocComponent (this.disableClickScriptFunc ? undefined : this.onClickHdlr); setHeight = (height: number) => { !this._props.suppressSetHeight && (this.layoutDoc._height = Math.min(NumCast(this.layoutDoc._maxHeight, Number.MAX_SAFE_INTEGER), height + 2 * NumCast(this.Document.borderWidth))); } // prettier-ignore setContentView = action((view: ViewBoxInterface) => { this._componentView = view; }); // prettier-ignore @@ -712,32 +712,34 @@ export class DocumentViewInternal extends DocComponent (this.aiContentsHeight() * (this._props.NativeWidth?.() || 1)) / (this._props.NativeHeight?.() || 1); aiContentsHeight = () => Math.max(10, this._props.PanelHeight() - this._aiWinHeight * this.uiBtnScaling); - aiEditor = () => ( - <> -
this.historyRef(this._oldAiWheel, (this._oldAiWheel = r))} - style={{ - transform: `scale(${this.uiBtnScaling})`, - height: this.aiContentsHeight() / this.uiBtnScaling, - width: ((this._props.PanelWidth() - this.aiContentsWidth()) * 0.95) / this.uiBtnScaling, - }}> - {this._componentView?.componentAIViewHistory?.() ?? null} -
-
this.historyRef(this._oldHistoryWheel, (this._oldHistoryWheel = r))}> -
- {this._componentView?.componentAIView?.() ?? null} - {this._props.DocumentView?.() ? : null} -
- - ); + @computed get aiEditor() { + return ( + <> +
this.historyRef(this._oldAiWheel, (this._oldAiWheel = r))} + style={{ + transform: `scale(${this.uiBtnScaling})`, + height: this.aiContentsHeight() / this.uiBtnScaling, + width: ((this._props.PanelWidth() - this.aiContentsWidth()) * 0.95) / this.uiBtnScaling, + }}> + {this._componentView?.componentAIViewHistory?.() ?? null} +
+
this.historyRef(this._oldHistoryWheel, (this._oldHistoryWheel = r))}> +
+ {this._componentView?.componentAIView?.() ?? null} + {this._props.DocumentView?.() ? : null} +
+ + ); + } @computed get tagsOverlay() { return (
(this.widgetDecorations ? this.widgetOverlay : null); + viewingAiEditor = () => (this._props.showAIEditor && this._componentView?.componentAIView?.() !== undefined ? this.aiEditor : null); @computed get viewBoxContents() { TraceMobx(); const isInk = this.layoutDoc._layout_isSvg && !this._props.LayoutTemplateString; @@ -770,8 +773,8 @@ export class DocumentViewInternal extends DocComponent
- {this._props.showAIEditor ? this.aiEditor() : this.tagsOverlayFunc()} + {this.viewingAiEditor() ?? this.tagsOverlayFunc()} {this.widgetOverlayFunc()} ); @@ -1256,6 +1259,7 @@ export class DocumentView extends DocComponent() { public get allLinks() { return this._docViewInternal?._allLinks ?? []; } // prettier-ignore public get TagBtnHeight() { return this._docViewInternal?.TagsBtnHeight; } // prettier-ignore public get UIBtnScaling() { return this._docViewInternal?.uiBtnScaling; } // prettier-ignore + public get HasAIEditor() { return !!this._docViewInternal?._componentView?.componentAIView?.(); } // prettier-ignore get LayoutFieldKey() { return Doc.LayoutFieldKey(this.Document, this._props.LayoutTemplateString); diff --git a/src/client/views/nodes/formattedText/DashFieldView.scss b/src/client/views/nodes/formattedText/DashFieldView.scss index 6db8abc7f..3734ad9cc 100644 --- a/src/client/views/nodes/formattedText/DashFieldView.scss +++ b/src/client/views/nodes/formattedText/DashFieldView.scss @@ -26,6 +26,7 @@ display: inline-block; font-weight: normal; background: rgba(0, 0, 0, 0.1); + align-content: center; cursor: default; } .dashFieldView-fieldSpan { diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index bef999e6d..fbe4fd294 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -1,5 +1,4 @@ /* eslint-disable no-use-before-define */ -import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@mui/material'; import { Property } from 'csstype'; @@ -21,7 +20,6 @@ import { AclAdmin, AclAugment, AclEdit, AclSelfEdit, DocCss, ForceServerWrite, U import { Id, ToString } from '../../../../fields/FieldSymbols'; import { InkTool } from '../../../../fields/InkField'; import { List } from '../../../../fields/List'; -import { PrefetchProxy } from '../../../../fields/Proxy'; import { RichTextField } from '../../../../fields/RichTextField'; import { ComputedField } from '../../../../fields/ScriptField'; import { BoolCast, Cast, DateCast, DocCast, FieldValue, NumCast, RTFCast, ScriptCast, StrCast } from '../../../../fields/Types'; @@ -35,7 +33,6 @@ import { DocUtils } from '../../../documents/DocUtils'; import { DictationManager } from '../../../util/DictationManager'; import { DragManager } from '../../../util/DragManager'; import { dropActionType } from '../../../util/DropActionTypes'; -import { MakeTemplate } from '../../../util/DropConverter'; import { LinkManager } from '../../../util/LinkManager'; import { RTFMarkup } from '../../../util/RTFMarkup'; import { SnappingManager } from '../../../util/SnappingManager'; @@ -855,42 +852,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { - Doc.setNativeView(this.Document); - this.layoutDoc.layout_autoHeightMargins = undefined; - }, 'set plain view'), - icon: 'eye', - }); - changeItems.push({ - description: 'metadata', - event: undoable(() => { - this.dataDoc.layout_meta = Cast(Doc.UserDoc().emptyHeader, Doc, null)?.layout; - this.Document.layout_fieldKey = 'layout_meta'; - setTimeout(() => { - this.layoutDoc._header_height = this.layoutDoc._layout_autoHeightMargins = 50; - }, 50); - }, 'set metadata view'), - icon: 'eye', - }); - const noteTypesDoc = Cast(Doc.UserDoc().template_notes, Doc, null); - DocListCast(noteTypesDoc?.data).forEach(note => { - const icon: IconProp = StrCast(note.icon) as IconProp; - changeItems.push({ - description: StrCast(note.title), - event: undoable( - () => { - this.layoutDoc.layout_autoHeightMargins = undefined; - Doc.setNativeView(this.Document); - DocUtils.makeCustomViewClicked(this.Document, Docs.Create.TreeDocument, StrCast(note.title), note); - }, - `set ${StrCast(note.title)} view}` - ), - icon: icon, - }); - }); const highlighting: ContextMenuProps[] = []; const noviceHighlighting = ['Audio Tags', 'My Text', 'Text from Others', 'Bold Text']; const expertHighlighting = [...noviceHighlighting, 'Important Items', 'Ignore Items', 'Disagree Items', 'By Recent Minute', 'By Recent Hour']; @@ -952,20 +913,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { - if (!this.layoutDoc.isTemplateDoc) { - MakeTemplate(this.Document); - } - Doc.UserDoc().defaultTextLayout = new PrefetchProxy(this.Document); - Doc.AddDocToList(Cast(Doc.UserDoc().template_notes, Doc, null), 'data', this.Document); - }, - icon: 'eye', - }); !appearance && appearanceItems.length && cm.addItem({ description: 'Appearance...', subitems: appearanceItems, icon: 'eye' }); const options = cm.findByDescription('Options...'); @@ -988,14 +935,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { - this.layoutDoc._layout_autoHeight = !this.layoutDoc._layout_autoHeight; - }, - icon: this.Document._layout_autoHeight ? 'lock' : 'unlock', - }); optionItems.push({ description: this.Document.savedAsSticker ? 'Sticker Saved!' : 'Save to Stickers', event: action(undoable(async () => await StickerPalette.addToPalette(this.Document), 'save to palette')), diff --git a/src/client/views/nodes/formattedText/RichTextRules.ts b/src/client/views/nodes/formattedText/RichTextRules.ts index 77c00537b..04315e886 100644 --- a/src/client/views/nodes/formattedText/RichTextRules.ts +++ b/src/client/views/nodes/formattedText/RichTextRules.ts @@ -113,7 +113,7 @@ export class RichTextRules { const inlineFieldKey = '$inline' + numInlines; // which field on the text document this annotation will write to const inlineLayoutKey = '$layout_' + inlineFieldKey; // the field holding the layout string that will render the inline annotation const textDocInline = Docs.Create.TextDocument('', { - _layout_fieldKey: inlineLayoutKey, + layout_fieldKey: inlineLayoutKey, _width: 75, _height: 35, annotationOn: this.Document[DocData], diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index e48337651..2db8d3b85 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -239,7 +239,7 @@ export class Doc extends RefField { public static get MyPublishedDocs() { return DocListCast(Doc.ActiveDashboard?.myPublishedDocs).concat(DocListCast(DocCast(Doc.UserDoc().myPublishedDocs)?.data)); } // prettier-ignore public static get MyDashboards() { return DocCast(Doc.UserDoc().myDashboards); } // prettier-ignore public static get MyTemplates() { return DocCast(Doc.UserDoc().myTemplates); } // prettier-ignore - public static get MyStickers() { return DocCast(Doc.UserDoc().myStickers); } // prettier-ignore + public static get MyStickers() { return DocCast(Doc.UserDoc().myStickers); } // prettier-ignore public static get MyLightboxDrawings() { return DocCast(Doc.UserDoc().myLightboxDrawings); } // prettier-ignore public static get MyImports() { return DocCast(Doc.UserDoc().myImports); } // prettier-ignore public static get MyFilesystem() { return DocCast(Doc.UserDoc().myFilesystem); } // prettier-ignore @@ -1062,14 +1062,14 @@ export namespace Doc { return ndoc; } - let _applyCount: number = 0; export function ApplyTemplate(templateDoc: Doc) { if (templateDoc) { const proto = new Doc(); + const applyCount = NumCast(templateDoc.dragFactory_count); proto.author = ClientUtils.CurrentUserEmail(); const target = Doc.MakeDelegate(proto); const targetKey = StrCast(templateDoc.layout_fieldKey, 'layout'); - const applied = ApplyTemplateTo(templateDoc, target, targetKey, templateDoc.title + '(...' + _applyCount++ + ')'); + const applied = ApplyTemplateTo(templateDoc, target, targetKey, templateDoc.title + '(...' + applyCount + ')'); target.layout_fieldKey = targetKey; //this and line above applied && (Doc.GetProto(applied).type = templateDoc.type); return applied; -- cgit v1.2.3-70-g09d2