aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/collections
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views/collections')
-rw-r--r--src/client/views/collections/CollectionCardDeckView.tsx3
-rw-r--r--src/client/views/collections/CollectionCarouselView.scss6
-rw-r--r--src/client/views/collections/CollectionCarouselView.tsx15
-rw-r--r--src/client/views/collections/CollectionMenu.tsx11
-rw-r--r--src/client/views/collections/CollectionNoteTakingView.tsx6
-rw-r--r--src/client/views/collections/CollectionStackingView.tsx15
-rw-r--r--src/client/views/collections/CollectionStackingViewFieldColumn.tsx12
-rw-r--r--src/client/views/collections/CollectionSubView.tsx32
-rw-r--r--src/client/views/collections/CollectionTreeView.tsx16
-rw-r--r--src/client/views/collections/CollectionView.tsx3
-rw-r--r--src/client/views/collections/FlashcardPracticeUI.tsx58
-rw-r--r--src/client/views/collections/TabDocView.scss12
-rw-r--r--src/client/views/collections/TabDocView.tsx27
-rw-r--r--src/client/views/collections/TreeView.tsx8
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormClusters.ts17
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx7
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss2
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx29
-rw-r--r--src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx4
-rw-r--r--src/client/views/collections/collectionFreeForm/ImageLabelBox.tsx20
-rw-r--r--src/client/views/collections/collectionFreeForm/MarqueeView.tsx8
-rw-r--r--src/client/views/collections/collectionGrid/CollectionGridView.tsx8
-rw-r--r--src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx112
-rw-r--r--src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx103
-rw-r--r--src/client/views/collections/collectionSchema/CollectionSchemaView.tsx2
-rw-r--r--src/client/views/collections/collectionSchema/SchemaCellField.tsx3
-rw-r--r--src/client/views/collections/collectionSchema/SchemaTableCell.tsx14
27 files changed, 298 insertions, 255 deletions
diff --git a/src/client/views/collections/CollectionCardDeckView.tsx b/src/client/views/collections/CollectionCardDeckView.tsx
index 756b37f99..50de7c601 100644
--- a/src/client/views/collections/CollectionCardDeckView.tsx
+++ b/src/client/views/collections/CollectionCardDeckView.tsx
@@ -23,7 +23,8 @@ import { undoable, UndoManager } from '../../util/UndoManager';
import { PinDocView, PinProps } from '../PinFuncs';
import { StyleProp } from '../StyleProp';
import { TagItem } from '../TagsView';
-import { DocumentView, DocumentViewProps } from '../nodes/DocumentView';
+import { DocumentViewProps } from '../nodes/DocumentContentsView';
+import { DocumentView } from '../nodes/DocumentView';
import { FocusViewOptions } from '../nodes/FocusViewOptions';
import './CollectionCardDeckView.scss';
import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView';
diff --git a/src/client/views/collections/CollectionCarouselView.scss b/src/client/views/collections/CollectionCarouselView.scss
index 544b3e262..962b590c8 100644
--- a/src/client/views/collections/CollectionCarouselView.scss
+++ b/src/client/views/collections/CollectionCarouselView.scss
@@ -1,12 +1,16 @@
.collectionCarouselView-outer {
height: 100%;
- position: relative;
+ position: absolute;
overflow: hidden;
display: flex;
+ transform-origin: top left;
+
.collectionCarouselView-caption {
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 a7d217076..2d3f8cb0e 100644
--- a/src/client/views/collections/CollectionCarouselView.tsx
+++ b/src/client/views/collections/CollectionCarouselView.tsx
@@ -115,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 (
<DocumentView
{...this._props}
ref={overlayFunc}
Document={doc}
+ TemplateDataDocument={doc.isTemplateDoc || doc.isTemplateForField ? this._props.TemplateDataDocument : undefined}
NativeWidth={returnZero}
NativeHeight={returnZero}
fitWidth={this._props.childLayoutFitWidth}
@@ -136,7 +138,6 @@ export class CollectionCarouselView extends CollectionSubView() {
renderDepth={this._props.renderDepth + 1}
LayoutTemplate={this._props.childLayoutTemplate}
LayoutTemplateString={this._props.childLayoutString}
- TemplateDataDocument={DocCast(Doc.Layout(doc).resolvedDataDoc)}
childFilters={this.childDocFilters}
focus={this.focus}
hideDecorations={BoolCast(this.layoutDoc.layout_hideDecorations)}
@@ -182,7 +183,15 @@ export class CollectionCarouselView extends CollectionSubView() {
}
@computed get content() {
- const captionProps = { ...this._props, NativeScaling: returnOne, PanelWidth: this.captionWidth, fieldKey: 'caption', setHeight: undefined, setContentView: undefined };
+ const captionProps = {
+ ...this._props, //
+ NativeScaling: returnOne,
+ PanelWidth: this.captionWidth,
+ fieldKey: 'caption',
+ setHeight: undefined,
+ setContentView: undefined,
+ noSidebar: true,
+ };
const carouselShowsCaptions = StrCast(this.layoutDoc._layout_showCaption);
return !this.curDoc() ? null : (
<>
@@ -242,11 +251,9 @@ export class CollectionCarouselView extends CollectionSubView() {
color: this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.Color) as string,
left: NumCast(this.layoutDoc._xMargin),
top: NumCast(this.layoutDoc._yMargin),
- transformOrigin: 'top left',
transform: `scale(${this.nativeScaling()})`,
width: `calc(${100 / this.nativeScaling()}% - ${(2 * NumCast(this.layoutDoc._xMargin)) / this.nativeScaling()}px)`,
height: `calc(${100 / this.nativeScaling()}% - ${(2 * NumCast(this.layoutDoc._yMargin)) / this.nativeScaling()}px)`,
- position: 'relative',
}}>
{this.content}
{this.navButtons}
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index c79610595..1576a8e4a 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -23,6 +23,7 @@ import { DefaultStyleProvider, returnEmptyDocViewList } from '../StyleProvider';
import { DocumentView, DocumentViewInternal } from '../nodes/DocumentView';
import './CollectionMenu.scss';
import { CollectionLinearView } from './collectionLinear';
+import { SettingsManager } from '../../util/SettingsManager';
interface CollectionMenuProps {
panelHeight: () => number;
@@ -118,7 +119,7 @@ export class CollectionMenu extends AntimodeMenu<CollectionMenuProps> {
<div className="hardCodedButtons">
<Toggle
toggleType={ToggleType.BUTTON}
- type={Type.PRIM}
+ type={Type.TERT}
color={SnappingManager.userColor}
onClick={this.props.toggleTopBar}
toggleStatus={this.props.topBarHeight() > 0}
@@ -127,7 +128,7 @@ export class CollectionMenu extends AntimodeMenu<CollectionMenuProps> {
/>
<Toggle
toggleType={ToggleType.BUTTON}
- type={Type.PRIM}
+ type={Type.TERT}
color={SnappingManager.userColor}
onClick={this._props.togglePropertiesFlyout}
toggleStatus={SnappingManager.PropertiesWidth > 0}
@@ -138,19 +139,17 @@ export class CollectionMenu extends AntimodeMenu<CollectionMenuProps> {
);
// dash col linear view buttons
- const contMenuButtons = (
+ return (
<div
className="collectionMenu-container"
style={{
- background: SnappingManager.userBackgroundColor,
+ background: SettingsManager.userBackgroundColor,
// borderColor: SettingsManager.userColor
}}>
{this.contMenuButtons}
{hardCodedButtons}
</div>
);
-
- return contMenuButtons;
}
}
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 (
<DocumentView
- ref={r => {
- 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 fd48a9dc1..4f60acb18 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -112,7 +112,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
@computed get columnWidth() {
const availableWidth = this._props.PanelWidth() - 2 * this.xMargin;
const cwid = availableWidth / (NumCast(this.Document._layout_columnCount) || this._props.PanelWidth() / NumCast(this.Document._layout_columnWidth, this._props.PanelWidth() / 4));
- return Math.min(availableWidth, this.isStackingView ? Number.MAX_VALUE : cwid - this.gridGap);
+ return Math.min(availableWidth, this.isStackingView ? availableWidth / (this.numGroupColumns || 1) : cwid - this.gridGap);
}
@computed get NodeWidth() {
@@ -675,12 +675,12 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
}
return35 = () => 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 : (
- <div className="buttonMenu-docBtn" style={{ width: NumCast(menuDoc._width, 30), height: NumCast(menuDoc._height, 30) }}>
+ return !this.menuBtnDoc ? null : (
+ <div className="buttonMenu-docBtn" style={{ width: NumCast(this.menuBtnDoc._width, 30), height: NumCast(this.menuBtnDoc._height, 30) }}>
<DocumentView
- Document={menuDoc}
+ Document={this.menuBtnDoc}
isContentActive={this.isContentActive}
isDocumentActive={this.isContentActive}
addDocument={this._props.addDocument}
@@ -728,13 +728,12 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
SetValue: this.addGroup,
contents: '+ ADD A GROUP',
};
- const buttonMenu = this.layoutDoc.layout_headerButton;
const noviceExplainer = this.layoutDoc.layout_explainer;
return (
<>
- {buttonMenu || noviceExplainer ? (
+ {this.menuBtnDoc || noviceExplainer ? (
<div className="documentButtonMenu">
- {buttonMenu ? this.buttonMenu : null}
+ {this.menuBtnDoc ? this.buttonMenu : null}
{Doc.noviceMode && noviceExplainer ? <div className="documentExplanation">{StrCast(noviceExplainer)}</div> : null}
</div>
) : null}
diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
index 3b9d167c6..66839ba7f 100644
--- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
+++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
@@ -7,7 +7,7 @@ import { Doc, DocListCast, Opt } from '../../../fields/Doc';
import { RichTextField } from '../../../fields/RichTextField';
import { PastelSchemaPalette, SchemaHeaderField } from '../../../fields/SchemaHeaderField';
import { ScriptField } from '../../../fields/ScriptField';
-import { BoolCast, NumCast } from '../../../fields/Types';
+import { BoolCast, DocCast, NumCast } from '../../../fields/Types';
import { ImageField } from '../../../fields/URLField';
import { TraceMobx } from '../../../fields/util';
import { emptyFunction } from '../../../Utils';
@@ -26,6 +26,7 @@ import { EditableView } from '../EditableView';
import { DocumentView } from '../nodes/DocumentView';
import { ObservableReactComponent } from '../ObservableReactComponent';
import './CollectionStackingView.scss';
+import { DocData } from '../../../fields/DocSymbols';
// So this is how we are storing a column
interface CSVFieldColumnProps {
@@ -270,7 +271,7 @@ export class CollectionStackingViewFieldColumn extends ObservableReactComponent<
event: () => {
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);
@@ -304,10 +305,8 @@ export class CollectionStackingViewFieldColumn extends ObservableReactComponent<
@computed get innards() {
TraceMobx();
const key = this._props.pivotField;
- const headings = this._props.headings();
const heading = this._heading;
const columnYMargin = this._props.headingObject ? 0 : this._props.yMargin;
- const uniqueHeadings = headings.map((i, idx) => headings.indexOf(i) === idx);
const noValueHeader = `NO ${key.toUpperCase()} VALUE`;
const evContents = heading || (this._props?.type === 'number' ? '0' : noValueHeader);
const headingView = this._props.headingObject ? (
@@ -317,7 +316,7 @@ export class CollectionStackingViewFieldColumn extends ObservableReactComponent<
ref={this._headerRef}
style={{
marginTop: this._props.yMargin,
- width: this._props.columnWidth / (uniqueHeadings.length + (this._props.chromeHidden ? 0 : 1) || 1),
+ width: this._props.columnWidth
}}>
{/* the default bucket (no key value) has a tooltip that describes what it is.
Further, it does not have a color and cannot be deleted. */}
@@ -360,7 +359,7 @@ export class CollectionStackingViewFieldColumn extends ObservableReactComponent<
margin: 'auto',
marginTop: this._props.dontCenter.includes('y') ? undefined : 'auto',
marginBottom: this._props.dontCenter.includes('y') ? undefined : 'auto',
- width: this._props.columnWidth / (uniqueHeadings.length + (this._props.chromeHidden ? 0 : 1) || 1),
+ width: this._props.columnWidth,
}}>
<div
key={`${heading}-stack`}
@@ -368,7 +367,6 @@ export class CollectionStackingViewFieldColumn extends ObservableReactComponent<
style={{
padding: `${columnYMargin}px ${0}px ${this._props.yMargin}px ${0}px`,
margin: this._props.dontCenter.includes('x') ? undefined : 'auto',
- // width: 'max-content', // singleColumn ? undefined : `${cols * (style.columnWidth + style.gridGap) + 2 * style.xMargin - style.gridGap}px`,
height: 'max-content',
position: 'relative',
gridGap: this._props.gridGap,
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index a43cf0755..375c0fe53 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -13,6 +13,7 @@ import { BoolCast, Cast, DateCast, NumCast, ScriptCast, StrCast, toList } from '
import { WebField } from '../../../fields/URLField';
import { GetEffectiveAcl, TraceMobx } from '../../../fields/util';
import { GestureUtils } from '../../../pen-gestures/GestureUtils';
+import { Upload } from '../../../server/SharedMediaTypes';
import { DocServer } from '../../DocServer';
import { Networking } from '../../Network';
import { DocUtils } from '../../documents/DocUtils';
@@ -24,11 +25,11 @@ import { ImageUtils } from '../../util/Import & Export/ImageUtils';
import { SnappingManager } from '../../util/SnappingManager';
import { UndoManager } from '../../util/UndoManager';
import { ViewBoxBaseComponent } from '../DocComponent';
+import { DocumentViewProps } from '../nodes/DocumentContentsView';
+import { DocumentView } from '../nodes/DocumentView';
import { FieldViewProps } from '../nodes/FieldView';
-import { DocumentView, DocumentViewProps } from '../nodes/DocumentView';
-import { FlashcardPracticeUI } from './FlashcardPracticeUI';
import { OpenWhere, OpenWhereMod } from '../nodes/OpenWhere';
-import { Upload } from '../../../server/SharedMediaTypes';
+import { FlashcardPracticeUI } from './FlashcardPracticeUI';
export enum docSortings {
Time = 'time',
@@ -108,11 +109,11 @@ export function CollectionSubView<X>() {
}
get dataDoc() {
- return this._props.TemplateDataDocument instanceof Doc && this.layoutDoc.isTemplateForField //
- ? this._props.TemplateDataDocument[DocData]
- : this.layoutDoc.resolvedDataDoc
- ? this._props.Document
- : 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
+ return this._props.TemplateDataDocument instanceof Doc && this.Document.isTemplateForField //
+ ? Doc.GetProto(this._props.TemplateDataDocument)
+ : 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() {
@@ -131,9 +132,9 @@ export function CollectionSubView<X>() {
hasChildDocs = () => this.childLayoutPairs.map(pair => pair.layout);
@computed get childLayoutPairs(): { layout: Doc; data: Doc }[] {
- const { Document: Document, TemplateDataDocument } = this._props;
+ const { TemplateDataDocument } = this._props;
const validPairs = this.childDocs
- .map(doc => Doc.GetLayoutDataDocPair(Document, !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 +300,7 @@ export function CollectionSubView<X>() {
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
@@ -589,7 +590,7 @@ export function CollectionSubView<X>() {
/**
* How much the content of the collection is being scaled based on its nesting and its fit-to-width settings
*/
- @computed get contentScaling() { return this.ScreenToLocalBoxXf().Scale; } // prettier-ignore
+ @computed get contentScaling() { return this.ScreenToLocalBoxXf().Scale * (!this._props.fitWidth?.(this.Document) ? this._props.NativeDimScaling?.()||1: 1); } // prettier-ignore
/**
* The maximum size a UI widget can be in collection coordinates based on not wanting the widget to visually obscure too much of the collection
* This takes the desired screen space size and converts into collection coordinates. It then returns the smaller of the converted
@@ -602,7 +603,12 @@ export function CollectionSubView<X>() {
*/
@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 1960e12bd..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';
@@ -187,7 +187,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
@action
addDoc = (docs: Doc | Doc[], relativeTo: Opt<Doc>, 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 &&
@@ -200,7 +200,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
onContextMenu = (): void => {
// 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<Partial<collectionTree
}
return35 = () => 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 : (
- <div className="buttonMenu-docBtn" style={{ width: NumCast(menuDoc._width, 30), height: NumCast(menuDoc._height, 30) }}>
+ return !this.menuBtnDoc ? null : (
+ <div className="buttonMenu-docBtn" style={{ width: NumCast(this.menuBtnDoc._width, 30), height: NumCast(this.menuBtnDoc._height, 30) }}>
<DocumentView
- Document={menuDoc}
- TemplateDataDocument={menuDoc}
+ Document={this.menuBtnDoc}
+ TemplateDataDocument={this.menuBtnDoc}
isContentActive={this._props.isContentActive}
isDocumentActive={returnTrue}
addDocument={this._props.addDocument}
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 7ba8989ce..c9af92a1b 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -130,7 +130,6 @@ export class CollectionView extends ViewBoxAnnotatableComponent<CollectionViewPr
{ description: 'Calendar', event: () => func(CollectionViewType.Calendar), icon: 'columns' },
{ description: 'Pivot', event: () => func(CollectionViewType.Pivot), icon: 'columns' },
{ description: 'Time', event: () => func(CollectionViewType.Time), icon: 'columns' },
- { description: 'Map', event: () => func(CollectionViewType.Map), icon: 'globe-americas' },
{ description: 'Grid', event: () => func(CollectionViewType.Grid), icon: 'th-list' },
];
@@ -162,7 +161,7 @@ export class CollectionView extends ViewBoxAnnotatableComponent<CollectionViewPr
if (this.Document.childClickedOpenTemplateView instanceof Doc) {
optionItems.push({ description: 'View Child Detailed Layout', event: () => this._props.addDocTab(this.Document.childClickedOpenTemplateView as Doc, OpenWhere.addRight), icon: 'project-diagram' });
}
- !Doc.noviceMode && optionItems.push({ description: `${this.layoutDoc._isLightbox ? 'Unset' : 'Set'} is Lightbox`, event: () => { this.layoutDoc._isLightbox = !this.layoutDoc._isLightbox; }, icon: 'project-diagram' }); // prettier-ignore
+ !Doc.noviceMode && optionItems.push({ description: `${this.dataDoc.$isLightbox ? 'Unset' : 'Set'} is Lightbox`, event: () => { this.dataDoc.$isLightbox = !this.dataDoc.$isLightbox; }, icon: 'project-diagram' }); // prettier-ignore
!options && cm.addItem({ description: 'Options...', subitems: optionItems, icon: 'hand-point-right' });
diff --git a/src/client/views/collections/FlashcardPracticeUI.tsx b/src/client/views/collections/FlashcardPracticeUI.tsx
index c071c5fb8..f24a8acb7 100644
--- a/src/client/views/collections/FlashcardPracticeUI.tsx
+++ b/src/client/views/collections/FlashcardPracticeUI.tsx
@@ -7,13 +7,16 @@ import { observer } from 'mobx-react';
import * as React from 'react';
import { returnFalse, returnZero, setupMoveUpEvents } from '../../../ClientUtils';
import { emptyFunction } from '../../../Utils';
-import { Doc, DocListCast } from '../../../fields/Doc';
+import { Doc, DocListCast, Opt } from '../../../fields/Doc';
import { BoolCast, NumCast, StrCast } from '../../../fields/Types';
import { SnappingManager } from '../../util/SnappingManager';
import { Transform } from '../../util/Transform';
import { ObservableReactComponent } from '../ObservableReactComponent';
-import { DocumentView, DocumentViewProps } from '../nodes/DocumentView';
+import { DocumentView } from '../nodes/DocumentView';
import './FlashcardPracticeUI.scss';
+import { StyleProp } from '../StyleProp';
+import { FieldViewProps } from '../nodes/FieldView';
+import { DocumentViewProps } from '../nodes/DocumentContentsView';
export enum practiceMode {
PRACTICE = 'practice',
@@ -60,8 +63,8 @@ export class FlashcardPracticeUI extends ObservableReactComponent<PracticeUIProp
@computed get filterDoc() { return DocListCast(Doc.MyContextMenuBtns.data).find(doc => doc.title === 'Filter'); } // prettier-ignore
@computed get practiceMode() { return this._props.allChildDocs().some(doc => doc._layout_flashcardType) ? StrCast(this._props.layoutDoc.practiceMode) : ''; } // prettier-ignore
- btnHeight = () => NumCast(this.filterDoc?.height) * Math.min(1, this._props.ScreenToLocalBoxXf().Scale);
- btnWidth = () => (!this.filterDoc ? 1 : (this.btnHeight() * NumCast(this.filterDoc._width)) / NumCast(this.filterDoc._height));
+ btnHeight = () => NumCast(this.filterDoc?.height);
+ btnWidth = () => (!this.filterDoc ? 1 : NumCast(this.filterDoc._width));
/**
* Sets the practice mode answer style for flashcards
@@ -131,7 +134,7 @@ export class FlashcardPracticeUI extends ObservableReactComponent<PracticeUIProp
<div
className="FlashcardPracticeUI-practiceModes"
style={{
- transform: this._props.ScreenToLocalBoxXf().Scale >= 1 ? undefined : `translateY(${this.btnHeight() / this._props.ScreenToLocalBoxXf().Scale - this.btnHeight()}px)`,
+ background: SnappingManager.userVariantColor,
}}>
<MultiToggle
tooltip="Practice flashcards one at a time"
@@ -139,7 +142,6 @@ export class FlashcardPracticeUI extends ObservableReactComponent<PracticeUIProp
color={SnappingManager.userColor}
background={SnappingManager.userVariantColor}
multiSelect={false}
- isToggle={false}
toggleStatus={!!this.practiceMode}
label="Practice"
items={[
@@ -159,7 +161,6 @@ export class FlashcardPracticeUI extends ObservableReactComponent<PracticeUIProp
color={SnappingManager.userColor}
background={SnappingManager.userVariantColor}
multiSelect={false}
- isToggle={false}
toggleStatus={!!this.practiceMode}
label={StrCast(this._props.layoutDoc.revealOp, flashcardRevealOp.FLIP)}
items={[
@@ -179,6 +180,12 @@ export class FlashcardPracticeUI extends ObservableReactComponent<PracticeUIProp
</div>
);
}
+ childStyleProvider = (doc: Doc | undefined, props: Opt<FieldViewProps>, property: string) => {
+ if (doc instanceof Doc && property === StyleProp.BackgroundColor) {
+ return SnappingManager.userVariantColor;
+ }
+ return this._props.docViewProps().styleProvider?.(doc, props, property);
+ };
tryFilterOut = (doc: Doc) => (this.practiceMode && doc?._layout_flashcardType && doc[this.practiceField] === practiceVal.CORRECT ? true : false); // show only cards that aren't marked as correct
render() {
return (
@@ -186,24 +193,27 @@ export class FlashcardPracticeUI extends ObservableReactComponent<PracticeUIProp
{this.emptyMessage}
{this.practiceButtons}
{this._props.layoutDoc._chromeHidden ? null : (
- <div className="FlashcardPracticeUI-menu" style={{ height: this.btnHeight(), width: this.btnHeight(), transform: `scale(${this._props.uiBtnScaling})` }}>
+ <div className="FlashcardPracticeUI-menu" style={{ height: this.btnHeight(), width: this.btnWidth(), transform: `scale(${this._props.uiBtnScaling})` }}>
{!this.filterDoc ? null : (
- <DocumentView
- {...this._props.docViewProps()}
- Document={this.filterDoc}
- TemplateDataDocument={undefined}
- PanelWidth={this.btnWidth}
- PanelHeight={this.btnHeight}
- NativeWidth={returnZero}
- NativeHeight={returnZero}
- hideDecorations={BoolCast(this._props.layoutDoc.layout_hideDecorations)}
- hideCaptions={true}
- hideFilterStatus={true}
- renderDepth={this._props.renderDepth + 1}
- fitWidth={undefined}
- showTags={false}
- setContentViewBox={undefined}
- />
+ <div style={{ background: SnappingManager.userVariantColor }}>
+ <DocumentView
+ {...this._props.docViewProps()}
+ Document={this.filterDoc}
+ TemplateDataDocument={undefined}
+ PanelWidth={this.btnWidth}
+ PanelHeight={this.btnHeight}
+ NativeWidth={returnZero}
+ NativeHeight={returnZero}
+ hideDecorations={BoolCast(this._props.layoutDoc.layout_hideDecorations)}
+ hideCaptions={true}
+ hideFilterStatus={true}
+ renderDepth={this._props.renderDepth + 1}
+ styleProvider={this.childStyleProvider}
+ fitWidth={undefined}
+ showTags={false}
+ setContentViewBox={undefined}
+ />
+ </div>
)}
{this.practiceModesMenu}
</div>
diff --git a/src/client/views/collections/TabDocView.scss b/src/client/views/collections/TabDocView.scss
index 397e35ca9..931cdac2b 100644
--- a/src/client/views/collections/TabDocView.scss
+++ b/src/client/views/collections/TabDocView.scss
@@ -4,7 +4,6 @@
height: 100%;
width: 100%;
}
-
input.lm_title:focus,
input.lm_title {
max-width: unset !important;
@@ -22,7 +21,6 @@ input.lm_title {
.lm_iconWrap {
display: flex;
color: black;
- width: 15px;
height: 15px;
align-items: center;
align-self: center;
@@ -30,6 +28,16 @@ input.lm_title {
margin: 3px;
border-radius: 20%;
+ width: auto;
+ svg:nth-of-type(2) {
+ display: none;
+ }
+ &:hover {
+ svg:nth-of-type(2) {
+ display: block;
+ }
+ }
+
.moreInfoDot {
background-color: white;
border-radius: 100%;
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 620be2726..568a08792 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -10,7 +10,7 @@ import ResizeObserver from 'resize-observer-polyfill';
import { ClientUtils, DashColor, lightOrDark, returnEmptyFilter, returnFalse, returnTrue, setupMoveUpEvents, simulateMouseClick } from '../../../ClientUtils';
import { emptyFunction } from '../../../Utils';
import { Doc, Opt, returnEmptyDoclist } from '../../../fields/Doc';
-import { DocData } from '../../../fields/DocSymbols';
+import { DocData, DocLayout } from '../../../fields/DocSymbols';
import { Id } from '../../../fields/FieldSymbols';
import { List } from '../../../fields/List';
import { FieldId } from '../../../fields/RefField';
@@ -41,6 +41,7 @@ import { CollectionDockingView } from './CollectionDockingView';
import { CollectionView } from './CollectionView';
import './TabDocView.scss';
import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView';
+import { Tooltip } from '@mui/material';
interface TabMinimapViewProps {
doc: Doc;
@@ -311,7 +312,7 @@ export class TabDocView extends ObservableReactComponent<TabDocViewProps> {
@observable _view: DocumentView | undefined = undefined;
@observable _forceInvalidateScreenToLocal = 0; // screentolocal is computed outside of react using a dom resize ovbserver. this hack allows the resize observer to trigger a react update
- @computed get layoutDoc() { return this._document && Doc.Layout(this._document); } // prettier-ignore
+ @computed get layoutDoc() { return this._document?.[DocLayout]; } // prettier-ignore
@computed get isUserActivated() { return TabDocView.IsSelected(this._document) || this._isAnyChildContentActive; } // prettier-ignore
@computed get isContentActive() { return this.isUserActivated || this._hovering; } // prettier-ignore
@@ -353,7 +354,6 @@ export class TabDocView extends ObservableReactComponent<TabDocViewProps> {
if (tab.element[0].children[1].children.length === 1) {
iconWrap.className = 'lm_iconWrap lm_moreInfo';
- iconWrap.title = 'click for menu, drag to embed in document';
const dragBtnDown = (e: React.PointerEvent) => {
setupMoveUpEvents(
this,
@@ -377,7 +377,26 @@ export class TabDocView extends ObservableReactComponent<TabDocViewProps> {
);
};
- const docIcon = <FontAwesomeIcon onPointerDown={dragBtnDown} icon={iconType} />;
+ const docIcon = (
+ <>
+ <Tooltip title="click for menu, drag to embed in document">
+ <FontAwesomeIcon onPointerDown={dragBtnDown} icon={iconType} />
+ </Tooltip>
+ <Tooltip title="click to open in lightbox">
+ <FontAwesomeIcon
+ onPointerDown={dragBtnDown}
+ icon="external-link-alt"
+ onClick={() => {
+ if (doc.layout_fieldKey === 'layout_icon') {
+ const odoc = Doc.GetEmbeddings(doc).find(embedding => !embedding.embedContainer) ?? Doc.MakeEmbedding(doc);
+ Doc.deiconifyView(odoc);
+ }
+ this.addDocTab(doc, OpenWhere.lightboxAlways);
+ }}
+ />
+ </Tooltip>
+ </>
+ );
const closeIcon = <FontAwesomeIcon icon="eye" />;
ReactDOM.createRoot(iconWrap).render(docIcon);
ReactDOM.createRoot(closeWrap).render(closeIcon);
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index cb7da8c84..4dc937864 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -7,7 +7,7 @@ import * as React from 'react';
import { ClientUtils, lightOrDark, return18, returnEmptyFilter, returnEmptyString, returnFalse, returnTrue, returnZero, setupMoveUpEvents, simulateMouseClick } from '../../../ClientUtils';
import { emptyFunction } from '../../../Utils';
import { Doc, DocListCast, Field, FieldType, Opt, StrListCast, returnEmptyDoclist } from '../../../fields/Doc';
-import { DocData } from '../../../fields/DocSymbols';
+import { DocData, DocLayout } from '../../../fields/DocSymbols';
import { Id } from '../../../fields/FieldSymbols';
import { List } from '../../../fields/List';
import { RichTextField } from '../../../fields/RichTextField';
@@ -156,7 +156,7 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> {
return this.Document[DocData];
}
@computed get layoutDoc() {
- return Doc.Layout(this.Document);
+ return this.Document[DocLayout];
}
@computed get fieldKey() {
return StrCast(this.Document._treeView_FieldKey, Doc.LayoutFieldKey(this.Document));
@@ -594,7 +594,7 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> {
const key = match[1];
const assign = match[2];
const val = match[3];
- Doc.SetField(doc, key, assign + val, false);
+ Doc.SetField(doc, key, assign + val);
return true;
}
return false;
@@ -1309,7 +1309,7 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> {
const indent = i === 0 ? undefined : (editTitle: boolean) => dentDoc(editTitle, docs[i - 1], undefined, treeViewRefs.get(docs[i - 1]));
const outdent = !parentCollectionDoc ? undefined : (editTitle: boolean) => dentDoc(editTitle, parentCollectionDoc, containerPrevSibling, parentTreeView instanceof TreeView ? parentTreeView._props.parentTreeView : undefined);
const addDocument = (doc: Doc | Doc[], annotationKey?: string, relativeTo?: Doc, before?: boolean) => add(doc, relativeTo ?? docs[i], before !== undefined ? before : false);
- const childLayout = Doc.Layout(pair.layout);
+ const childLayout = pair.layout[DocLayout];
const rowHeight = () => {
const aspect = Doc.NativeAspect(childLayout);
return aspect ? Math.min(NumCast(childLayout._width), rowWidth()) / aspect : NumCast(childLayout._height);
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormClusters.ts b/src/client/views/collections/collectionFreeForm/CollectionFreeFormClusters.ts
index 3838852dd..903d92c90 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormClusters.ts
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormClusters.ts
@@ -31,16 +31,14 @@ export class CollectionFreeFormClusters {
get selectDocuments() { return this._view.selectDocuments; } // prettier-ignore
static overlapping(doc1: Doc, doc2: Doc, clusterDistance: number) {
- const doc2Layout = Doc.Layout(doc2);
- const doc1Layout = Doc.Layout(doc1);
const x2 = NumCast(doc2.x) - clusterDistance;
const y2 = NumCast(doc2.y) - clusterDistance;
- const w2 = NumCast(doc2Layout._width) + clusterDistance;
- const h2 = NumCast(doc2Layout._height) + clusterDistance;
+ const w2 = NumCast(doc2._width) + clusterDistance;
+ const h2 = NumCast(doc2._height) + clusterDistance;
const x = NumCast(doc1.x) - clusterDistance;
const y = NumCast(doc1.y) - clusterDistance;
- const w = NumCast(doc1Layout._width) + clusterDistance;
- const h = NumCast(doc1Layout._height) + clusterDistance;
+ const w = NumCast(doc1._width) + clusterDistance;
+ const h = NumCast(doc1._height) + clusterDistance;
return doc1.z === doc2.z && intersectRect({ left: x, top: y, width: w, height: h }, { left: x2, top: y2, width: w2, height: h2 });
}
handlePointerDown(probe: number[]) {
@@ -49,12 +47,11 @@ export class CollectionFreeFormClusters {
.reduce((cluster, cd) => {
const grouping = this.Document._freeform_useClusters ? NumCast(cd.layout_cluster, -1) : NumCast(cd.group, -1);
if (grouping !== -1) {
- const layoutDoc = Doc.Layout(cd);
const cx = NumCast(cd.x) - this._clusterDistance / 2;
const cy = NumCast(cd.y) - this._clusterDistance / 2;
- const cw = NumCast(layoutDoc._width) + this._clusterDistance;
- const ch = NumCast(layoutDoc._height) + this._clusterDistance;
- return !layoutDoc.z && intersectRect({ left: cx, top: cy, width: cw, height: ch }, { left: probe[0], top: probe[1], width: 1, height: 1 }) ? grouping : cluster;
+ const cw = NumCast(cd._width) + this._clusterDistance;
+ const ch = NumCast(cd._height) + this._clusterDistance;
+ return !cd.z && intersectRect({ left: cx, top: cy, width: cw, height: ch }, { left: probe[0], top: probe[1], width: 1, height: 1 }) ? grouping : cluster;
}
return cluster;
}, -1);
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
index 4ea1de680..158bac7ba 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
@@ -1,5 +1,6 @@
/* eslint-disable no-use-before-define */
import { Doc, Field, FieldType, FieldResult } from '../../../../fields/Doc';
+import { DocLayout } from '../../../../fields/DocSymbols';
import { Id, ToString } from '../../../../fields/FieldSymbols';
import { ObjectField } from '../../../../fields/ObjectField';
import { RefField } from '../../../../fields/RefField';
@@ -237,7 +238,7 @@ export function computePivotLayout(poolData: Map<string, PoolData>, pivotDoc: Do
payload: val,
});
val?.docs.forEach((doc, i) => {
- const layoutDoc = Doc.Layout(doc);
+ const layoutDoc = doc[DocLayout];
let wid = pivotAxisWidth;
let hgt = pivotAxisWidth / (Doc.NativeAspect(layoutDoc) || 1);
if (hgt > pivotAxisWidth) {
@@ -249,7 +250,7 @@ export function computePivotLayout(poolData: Map<string, PoolData>, pivotDoc: Do
y: -y + (pivotAxisWidth - hgt) / 2,
width: wid,
height: hgt,
- backgroundColor: StrCast(layoutDoc.backgroundColor, 'white'),
+ backgroundColor: StrCast(doc.backgroundColor, 'white'),
pair: { layout: doc },
replica: val.replicas[i],
});
@@ -362,7 +363,7 @@ export function computeTimelineLayout(poolData: Map<string, PoolData>, pivotDoc:
function layoutDocsAtTime(keyDocs: Doc[], key: number) {
keyDocs.forEach(doc => {
const stack = findStack(x, stacking);
- const layoutDoc = Doc.Layout(doc);
+ const layoutDoc = doc[DocLayout];
let wid = pivotAxisWidth;
let hgt = pivotAxisWidth / (Doc.NativeAspect(layoutDoc) || 1);
if (hgt > pivotAxisWidth) {
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss
index cce0ff684..6c47a71b0 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss
@@ -41,7 +41,7 @@
transition: background-color 1s ease 0s;
}
.collectionfreeformview-mask {
- mix-blend-mode: multiply;
+ mix-blend-mode: hard-light;
background-color: rgba(0, 0, 0, 0.8);
}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 7fd5d71fd..626538976 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -11,7 +11,7 @@ import ReactLoading from 'react-loading';
import { ClientUtils, DashColor, lightOrDark, OmitKeys, returnFalse, returnZero, setupMoveUpEvents, UpdateIcon } from '../../../../ClientUtils';
import { DateField } from '../../../../fields/DateField';
import { Doc, DocListCast, Field, FieldType, Opt, StrListCast } from '../../../../fields/Doc';
-import { DocData, Height, Width } from '../../../../fields/DocSymbols';
+import { DocData, DocLayout, Height, Width } from '../../../../fields/DocSymbols';
import { Id } from '../../../../fields/FieldSymbols';
import { InkData, InkEraserTool, InkField, InkInkTool, InkTool, Segment } from '../../../../fields/InkField';
import { List } from '../../../../fields/List';
@@ -286,7 +286,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
// this search order, for example, allows icons of cropped images to find the panx/pany/zoom on the cropped image's data doc instead of the usual layout doc because the zoom/panX/panY define the cropped image
panX = () => 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(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);
@@ -440,7 +440,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
const dropPos = this.Document._currentFrame !== undefined ? [NumCast(dvals.x), NumCast(dvals.y)] : [NumCast(refDoc.x), NumCast(refDoc.y)];
docDragData.droppedDocuments.forEach((d, i) => {
- const layoutDoc = Doc.Layout(d);
+ const layoutDoc = d[DocLayout];
const delta = Utils.rotPt(x - dropPos[0], y - dropPos[1], fromScreenXf.Rotate);
if (this.Document._currentFrame !== undefined) {
CollectionFreeFormDocumentView.setupKeyframes([d], NumCast(this.Document._currentFrame), false);
@@ -1440,9 +1440,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
}
calculatePanIntoView = (doc: Doc, xf: Transform, scale?: number) => {
- const layoutdoc = Doc.Layout(doc);
const pt = xf.transformPoint(NumCast(doc.x), NumCast(doc.y));
- const pt2 = xf.transformPoint(NumCast(doc.x) + NumCast(layoutdoc._width), NumCast(doc.y) + NumCast(layoutdoc._height));
+ const pt2 = xf.transformPoint(NumCast(doc.x) + NumCast(doc._width), NumCast(doc.y) + NumCast(doc._height));
const bounds = { left: pt[0], right: pt2[0], top: pt[1], bot: pt2[1], width: pt2[0] - pt[0], height: pt2[1] - pt[1] };
if (scale !== undefined) {
@@ -1489,9 +1488,9 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
* @returns whether the new text doc was created and added successfully
*/
createTextDocCopy = undoable((textBox: FormattedTextBox, below: boolean) => {
- const textDoc = DocCast(textBox.Document.rootDocument, textBox.Document);
+ const textDoc = DocCast(textBox.Document);
const newDoc = Doc.MakeCopy(textDoc, true);
- newDoc['$' + Doc.LayoutFieldKey(newDoc, textBox._props.LayoutTemplateString)] = undefined; // the copy should not copy the text contents of it source, just the render style
+ newDoc['$' + Doc.LayoutFieldKey(newDoc)] = undefined; // the copy should not copy the text contents of it source, just the render style
newDoc.x = NumCast(textDoc.x) + (below ? 0 : NumCast(textDoc._width) + 10);
newDoc.y = NumCast(textDoc.y) + (below ? NumCast(textDoc._height) + 10 : 0);
DocumentView.SetSelectOnLoad(newDoc);
@@ -1588,7 +1587,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
}
case undefined:
case OpenWhere.lightbox:
- if (this.layoutDoc._isLightbox) {
+ if (this.dataDoc.$isLightbox) {
this._lightboxDoc = docs[0];
return true;
}
@@ -1600,14 +1599,14 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
getCalculatedPositions(pair: { layout: Doc; data?: Doc }): PoolData {
const random = (min: number, max: number, x: number, y: number) => /* min should not be equal to max */ min + (((Math.abs(x * y) * 9301 + 49297) % 233280) / 233280) * (max - min);
const childDoc = pair.layout;
- const childDocLayout = Doc.Layout(childDoc);
const layoutFrameNumber = Cast(this.Document._currentFrame, 'number'); // frame number that container is at which determines layout frame values
- const contentFrameNumber = Cast(childDocLayout._currentFrame, 'number', layoutFrameNumber ?? null); // frame number that content is at which determines what content is displayed
- const { z, zIndex } = childDoc;
+ const contentFrameNumber = Cast(childDoc._currentFrame, 'number', layoutFrameNumber ?? null); // frame number that content is at which determines what content is displayed
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ const { z, zIndex, stroke_isInkMask } = childDoc;
const { backgroundColor, color } = contentFrameNumber === undefined ? { backgroundColor: undefined, color: undefined } : CollectionFreeFormDocumentView.getStringValues(childDoc, contentFrameNumber);
const { x, y, autoDim, _width, _height, opacity, _rotation } =
layoutFrameNumber === undefined // -1 for width/height means width/height should be PanelWidth/PanelHeight (prevents collectionfreeformdocumentview width/height from getting out of synch with panelWIdth/Height which causes detailView to re-render and lose focus because HTMLtag scaling gets set to a bad intermediate value)
- ? { autoDim: 1, _width: Cast(childDoc._width, 'number'), _height: Cast(childDoc._height, 'number'), _rotation: Cast(childDocLayout._rotation, 'number'), x: childDoc.x, y: childDoc.y, opacity: this._props.childOpacity?.() }
+ ? { autoDim: 1, _width: Cast(childDoc._width, 'number'), _height: Cast(childDoc._height, 'number'), _rotation: Cast(childDoc._rotation, 'number'), x: childDoc.x, y: childDoc.y, opacity: this._props.childOpacity?.() }
: CollectionFreeFormDocumentView.getValues(childDoc, layoutFrameNumber);
// prettier-ignore
const rotation = Cast(_rotation,'number',
@@ -1625,8 +1624,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
zIndex: Cast(zIndex, 'number'),
width: _width,
height: _height,
- transition: StrCast(childDocLayout.dataTransition),
- showTags: BoolCast(childDocLayout.showTags) || BoolCast(this.Document.showChildTags) || BoolCast(this.Document._layout_showTags),
+ transition: StrCast(childDoc.dataTransition),
+ showTags: BoolCast(childDoc.showTags) || BoolCast(this.Document.showChildTags) || BoolCast(this.Document._layout_showTags),
pointerEvents: Cast(childDoc.pointerEvents, 'string', null),
pair,
replica: '',
@@ -1719,7 +1718,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
elements.push({
ele: this.getChildDocView(entry[1]),
bounds: entry[1].opacity === 0 ? { payload: undefined, type: '', ...entry[1], width: 0, height: 0 } : { payload: undefined, type: '', ...entry[1] },
- inkMask: BoolCast(entry[1].pair.layout.stroke_isInkMask) ? NumCast(entry[1].pair.layout.opacity, 1) : -1,
+ inkMask: BoolCast(entry[1].pair.layout?.$stroke_isInkMask) ? NumCast(entry[1].pair.layout.opacity, 1) : -1,
})
);
diff --git a/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx b/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx
index b40189d76..c7aa410c6 100644
--- a/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx
+++ b/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx
@@ -11,7 +11,7 @@ import { emptyFunction } from '../../../../Utils';
import { Doc, DocListCast, Opt } from '../../../../fields/Doc';
import { DocData } from '../../../../fields/DocSymbols';
import { List } from '../../../../fields/List';
-import { DocCast, ImageCast, NumCast, StrCast } from '../../../../fields/Types';
+import { DocCast, ImageCastToNameType, NumCast, StrCast } from '../../../../fields/Types';
import { DocumentType } from '../../../documents/DocumentTypes';
import { Docs } from '../../../documents/Documents';
import { DragManager } from '../../../util/DragManager';
@@ -187,7 +187,7 @@ export class UniqueFaceBox extends ViewBoxBaseComponent<FieldViewProps>() {
ele?.addEventListener('wheel', this.onPassiveWheel, { passive: false });
})}>
{FaceRecognitionHandler.UniqueFaceImages(this.Document).map((doc, i) => {
- const [name, type] = ImageCast(doc[Doc.LayoutFieldKey(doc)])?.url.href.split('.') ?? ['-missing-', '.png'];
+ const [name, type] = ImageCastToNameType(doc[Doc.LayoutFieldKey(doc)]) ?? ['-missing-', '.png'];
return (
<div
className="image-wrapper"
diff --git a/src/client/views/collections/collectionFreeForm/ImageLabelBox.tsx b/src/client/views/collections/collectionFreeForm/ImageLabelBox.tsx
index c983d7c26..7c8ccb92d 100644
--- a/src/client/views/collections/collectionFreeForm/ImageLabelBox.tsx
+++ b/src/client/views/collections/collectionFreeForm/ImageLabelBox.tsx
@@ -10,7 +10,7 @@ import { imageUrlToBase64 } from '../../../../ClientUtils';
import { Utils, numberRange } from '../../../../Utils';
import { Doc, NumListCast, Opt } from '../../../../fields/Doc';
import { List } from '../../../../fields/List';
-import { ImageCast } from '../../../../fields/Types';
+import { ImageCastToNameType, ImageCastWithSuffix } from '../../../../fields/Types';
import { gptGetEmbedding, gptImageLabel } from '../../../apis/gpt/GPT';
import { DocumentType } from '../../../documents/DocumentTypes';
import { Docs } from '../../../documents/Documents';
@@ -165,8 +165,8 @@ export class ImageLabelBox extends ViewBoxBaseComponent<FieldViewProps>() {
const imageInfos = this._selectedImages.map(async doc => {
if (!doc.$tags_chat) {
- const [name, type] = ImageCast(doc[Doc.LayoutFieldKey(doc)]).url.href.split('.');
- return imageUrlToBase64(`${name}_o.${type}`).then(hrefBase64 =>
+ const url = ImageCastWithSuffix(doc[Doc.LayoutFieldKey(doc)], '_o') ?? '';
+ return imageUrlToBase64(url).then(hrefBase64 =>
!hrefBase64 ? undefined :
gptImageLabel(hrefBase64,'Give three labels to describe this image.').then(labels =>
({ doc, labels }))) ; // prettier-ignore
@@ -199,13 +199,11 @@ export class ImageLabelBox extends ViewBoxBaseComponent<FieldViewProps>() {
groupImagesInBox = action(async () => {
this.startLoading();
- for (const doc of this._selectedImages) {
- for (let index = 0; index < (doc.$tags_chat as List<string>).length; index++) {
- const label = (doc.$tags_chat as List<string>)[index];
- const embedding = await gptGetEmbedding(label);
- doc[`$tags_embedding_${index + 1}`] = new List<number>(embedding);
- }
- }
+ await Promise.all(
+ this._selectedImages
+ .map(doc => ({ doc, labels: doc.$tags_chat as List<string> }))
+ .map(({ doc, labels }) => labels.map((label, index) => gptGetEmbedding(label).then(embedding => (doc[`$tags_embedding_${index + 1}`] = new List<number>(embedding)))))
+ );
const labelToEmbedding = new Map<string, number[]>();
// Create embeddings for the labels.
@@ -312,7 +310,7 @@ export class ImageLabelBox extends ViewBoxBaseComponent<FieldViewProps>() {
{this._displayImageInformation ? (
<div className="image-information-list">
{this._selectedImages.map(doc => {
- const [name, type] = ImageCast(doc[Doc.LayoutFieldKey(doc)]).url.href.split('.');
+ const [name, type] = ImageCastToNameType(doc[Doc.LayoutFieldKey(doc)]);
return (
<div className="image-information" style={{ borderColor: SettingsManager.userColor }} key={Utils.GenerateGuid()}>
<img
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index eaa8826ed..5fbf72f39 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -8,7 +8,7 @@ import { AclAdmin, AclAugment, AclEdit, DocData } from '../../../../fields/DocSy
import { Id } from '../../../../fields/FieldSymbols';
import { InkData, InkTool } from '../../../../fields/InkField';
import { List } from '../../../../fields/List';
-import { Cast, NumCast, StrCast } from '../../../../fields/Types';
+import { Cast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types';
import { ImageField } from '../../../../fields/URLField';
import { GetEffectiveAcl } from '../../../../fields/util';
import { DocUtils } from '../../../documents/DocUtils';
@@ -18,7 +18,6 @@ import { SnappingManager, freeformScrollMode } from '../../../util/SnappingManag
import { Transform } from '../../../util/Transform';
import { UndoManager, undoBatch } from '../../../util/UndoManager';
import { ContextMenu } from '../../ContextMenu';
-import { MainView } from '../../MainView';
import { ObservableReactComponent } from '../../ObservableReactComponent';
import { MarqueeViewBounds } from '../../PinFuncs';
import { PreviewCursor } from '../../PreviewCursor';
@@ -442,7 +441,7 @@ export class MarqueeView extends ObservableReactComponent<SubCollectionViewProps
if (groupButton) {
this._selectedDocs = this.marqueeSelect(false, DocumentType.IMG);
ImageLabelBoxData.Instance.setData(this._selectedDocs);
- MainView.Instance.expandFlyout(groupButton);
+ ScriptCast(groupButton.onClick)?.script.run({ this: groupButton });
}
};
@@ -591,8 +590,7 @@ export class MarqueeView extends ObservableReactComponent<SubCollectionViewProps
marqueeSelect = (selectBackgrounds: boolean = false, docType: DocumentType | undefined = undefined) => {
const selection: Doc[] = [];
const selectFunc = (doc: Doc) => {
- const layoutDoc = Doc.Layout(doc);
- const bounds = { left: NumCast(doc.x), top: NumCast(doc.y), width: NumCast(layoutDoc._width), height: NumCast(layoutDoc._height) };
+ const bounds = { left: NumCast(doc.x), top: NumCast(doc.y), width: NumCast(doc._width), height: NumCast(doc._height) };
if (!this._lassoFreehand) {
intersectRect(bounds, this.Bounds) && selection.push(doc);
} else {
diff --git a/src/client/views/collections/collectionGrid/CollectionGridView.tsx b/src/client/views/collections/collectionGrid/CollectionGridView.tsx
index e7f1de7f1..a7603a45b 100644
--- a/src/client/views/collections/collectionGrid/CollectionGridView.tsx
+++ b/src/client/views/collections/collectionGrid/CollectionGridView.tsx
@@ -182,17 +182,17 @@ export class CollectionGridView extends CollectionSubView() {
isChildContentActive = () => (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) => (
<DocumentView
{...this._props}
- Document={layout}
- TemplateDataDocument={layout.resolvedDataDoc as Doc}
+ Document={childLayout}
+ TemplateDataDocument={childLayout.isTemplateDoc || childLayout.isTemplateForField ? this._props.TemplateDataDocument : undefined}
NativeWidth={returnZero}
NativeHeight={returnZero}
fitWidth={this._props.childLayoutFitWidth}
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
index 8aae24df0..adaceb053 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
@@ -1,14 +1,17 @@
+import { Button, IconButton } from '@dash/components';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Tooltip } from '@mui/material';
-import { Button, IconButton } from '@dash/components';
import { action, computed, makeObservable, observable } from 'mobx';
import { observer } from 'mobx-react';
+import { computedFn } from 'mobx-utils';
import * as React from 'react';
import { FaChevronRight } from 'react-icons/fa';
import { Doc, DocListCast } from '../../../../fields/Doc';
import { BoolCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types';
import { DragManager } from '../../../util/DragManager';
+import { dropActionType } from '../../../util/DropActionTypes';
import { SettingsManager } from '../../../util/SettingsManager';
+import { SnappingManager } from '../../../util/SnappingManager';
import { Transform } from '../../../util/Transform';
import { undoable } from '../../../util/UndoManager';
import { DocumentView } from '../../nodes/DocumentView';
@@ -16,8 +19,6 @@ import { CollectionSubView, SubCollectionViewProps } from '../CollectionSubView'
import './CollectionMulticolumnView.scss';
import ResizeBar from './MulticolumnResizer';
import WidthLabel from './MulticolumnWidthLabel';
-import { dropActionType } from '../../../util/DropActionTypes';
-import { SnappingManager } from '../../../util/SnappingManager';
interface WidthSpecifier {
magnitude: number;
@@ -197,16 +198,14 @@ export class CollectionMulticolumnView extends CollectionSubView() {
* documents before the target.
*/
private lookupIndividualTransform = (layout: Doc) => {
- if (this.columnUnitLength === 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(-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 (
- <DocumentView
- Document={childLayout}
- TemplateDataDocument={childLayout.resolvedDataDoc as Doc}
- styleProvider={this._props.styleProvider}
- containerViewPath={this.childContainerViewPath}
- LayoutTemplate={this._props.childLayoutTemplate}
- LayoutTemplateString={this._props.childLayoutString}
- renderDepth={this._props.renderDepth + 1}
- PanelWidth={width}
- PanelHeight={height}
- rootSelected={this.rootSelected}
- dragAction={StrCast(this.Document.childDragAction, this._props.childDragAction) as dropActionType}
- onClickScript={this.onChildClickHandler}
- onDoubleClickScript={this.onChildDoubleClickHandler}
- suppressSetHeight
- ScreenToLocalTransform={dxf}
- isContentActive={this.isChildContentActive}
- isDocumentActive={this._props.childDocumentsActive?.() || this.Document._childDocumentsActive ? this._props.isDocumentActive : this.isContentActive}
- hideResizeHandles={!!(childLayout.layout_fitWidth || this._props.childHideResizeHandles)}
- hideDecorationTitle={this._props.childHideDecorationTitle}
- fitContentsToBox={this._props.fitContentsToBox}
- focus={this._props.focus}
- childFilters={this.childDocFilters}
- childFiltersByRanges={this.childDocRangeFilters}
- searchFilterDocs={this.searchFilterDocs}
- dontRegisterView={this._props.dontRegisterView}
- addDocument={this._props.addDocument}
- moveDocument={this._props.moveDocument}
- removeDocument={this._props.removeDocument}
- whenChildContentsActiveChanged={this._props.whenChildContentsActiveChanged}
- addDocTab={this._props.addDocTab}
- pinToPres={this._props.pinToPres}
- dontCenter={StrCast(this.layoutDoc.layout_dontCenter) as 'x' | 'y' | 'xy'}
- />
- );
- };
+ .scale(this._props.NativeDimScaling?.() || 1)
+ );
+ getDisplayDoc = (childLayout: Doc) => (
+ <DocumentView
+ Document={childLayout}
+ TemplateDataDocument={childLayout.isTemplateDoc || childLayout.isTemplateForField ? this._props.TemplateDataDocument : undefined}
+ styleProvider={this._props.styleProvider}
+ containerViewPath={this.childContainerViewPath}
+ LayoutTemplate={this._props.childLayoutTemplate}
+ LayoutTemplateString={this._props.childLayoutString}
+ renderDepth={this._props.renderDepth + 1}
+ PanelWidth={this.childWidth(childLayout)}
+ PanelHeight={this.childHeight}
+ rootSelected={this.rootSelected}
+ dragAction={StrCast(this.Document.childDragAction, this._props.childDragAction) as dropActionType}
+ onClickScript={this.onChildClickHandler}
+ onDoubleClickScript={this.onChildDoubleClickHandler}
+ suppressSetHeight
+ ScreenToLocalTransform={this.childXf(childLayout)}
+ isContentActive={this.isChildContentActive}
+ isDocumentActive={this._props.childDocumentsActive?.() || this.Document._childDocumentsActive ? this._props.isDocumentActive : this.isContentActive}
+ hideResizeHandles={!!(childLayout.layout_fitWidth || this._props.childHideResizeHandles)}
+ hideDecorationTitle={this._props.childHideDecorationTitle}
+ fitContentsToBox={this._props.fitContentsToBox}
+ focus={this._props.focus}
+ childFilters={this.childDocFilters}
+ childFiltersByRanges={this.childDocRangeFilters}
+ searchFilterDocs={this.searchFilterDocs}
+ dontRegisterView={this._props.dontRegisterView}
+ addDocument={this._props.addDocument}
+ moveDocument={this._props.moveDocument}
+ removeDocument={this._props.removeDocument}
+ whenChildContentsActiveChanged={this._props.whenChildContentsActiveChanged}
+ addDocTab={this._props.addDocTab}
+ pinToPres={this._props.pinToPres}
+ dontCenter={StrCast(this.layoutDoc.layout_dontCenter) as 'x' | 'y' | 'xy'}
+ />
+ );
+
/**
* @returns the resolved list of rendered child documents, displayed
* at their resolved pixel widths, each separated by a resizer.
@@ -315,7 +315,6 @@ export class CollectionMulticolumnView extends CollectionSubView() {
const collector: JSX.Element[] = [];
this.childLayouts.forEach((layout, i) => {
collector.push(
- // eslint-disable-next-line react/no-array-index-key
<Tooltip title={'Doc: ' + StrCast(layout.title)} key={'wrapper' + i}>
<div className="document-wrapper" style={{ flexDirection: 'column', width: this.lookupPixels(layout) }}>
{this.getDisplayDoc(layout)}
@@ -327,7 +326,6 @@ export class CollectionMulticolumnView extends CollectionSubView() {
</Tooltip>,
<ResizeBar
width={resizerWidth}
- // eslint-disable-next-line react/no-array-index-key
key={'resizer' + i}
styleProvider={this._props.styleProvider}
isContentActive={this._props.isContentActive}
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
index bda8e91ac..27c41583c 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
@@ -1,5 +1,6 @@
import { action, computed, makeObservable } from 'mobx';
import { observer } from 'mobx-react';
+import { computedFn } from 'mobx-utils';
import * as React from 'react';
import { Doc, DocListCast } from '../../../../fields/Doc';
import { BoolCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types';
@@ -178,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
};
@@ -243,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 (
- <DocumentView
- Document={layout}
- TemplateDataDocument={layout.resolvedDataDoc as Doc}
- styleProvider={this._props.styleProvider}
- containerViewPath={this.childContainerViewPath}
- LayoutTemplate={this._props.childLayoutTemplate}
- LayoutTemplateString={this._props.childLayoutString}
- renderDepth={this._props.renderDepth + 1}
- PanelWidth={width}
- PanelHeight={height}
- rootSelected={this.rootSelected}
- dragAction={StrCast(this.Document.childDragAction, this._props.childDragAction) as dropActionType}
- onClickScript={this.onChildClickHandler}
- onDoubleClickScript={this.onChildDoubleClickHandler}
- ScreenToLocalTransform={dxf}
- isContentActive={this.isChildContentActive}
- isDocumentActive={this._props.childDocumentsActive?.() || this.Document._childDocumentsActive ? this._props.isDocumentActive : this.isContentActive}
- hideResizeHandles={!!(layout.layout_fitWidth || this._props.childHideResizeHandles)}
- hideDecorationTitle={this._props.childHideDecorationTitle}
- fitContentsToBox={this._props.fitContentsToBox}
- focus={this._props.focus}
- childFilters={this.childDocFilters}
- childFiltersByRanges={this.childDocRangeFilters}
- searchFilterDocs={this.searchFilterDocs}
- dontRegisterView={this._props.dontRegisterView}
- addDocument={this._props.addDocument}
- moveDocument={this._props.moveDocument}
- removeDocument={this._props.removeDocument}
- whenChildContentsActiveChanged={this._props.whenChildContentsActiveChanged}
- addDocTab={this._props.addDocTab}
- pinToPres={this._props.pinToPres}
- dontCenter={StrCast(this.layoutDoc.layout_dontCenter) as 'y' | 'x' | 'xy'}
- />
- );
- };
+ .scale(this._props.NativeDimScaling?.() || 1)
+ );
+
+ getDisplayDoc = (childLayout: Doc) => (
+ <DocumentView
+ Document={childLayout}
+ TemplateDataDocument={childLayout.isTemplateDoc || childLayout.isTemplateForField ? this._props.TemplateDataDocument : undefined}
+ styleProvider={this._props.styleProvider}
+ containerViewPath={this.childContainerViewPath}
+ LayoutTemplate={this._props.childLayoutTemplate}
+ LayoutTemplateString={this._props.childLayoutString}
+ renderDepth={this._props.renderDepth + 1}
+ PanelWidth={this.childWidth}
+ PanelHeight={this.childHeight(childLayout)}
+ rootSelected={this.rootSelected}
+ dragAction={StrCast(this.Document.childDragAction, this._props.childDragAction) as dropActionType}
+ onClickScript={this.onChildClickHandler}
+ onDoubleClickScript={this.onChildDoubleClickHandler}
+ ScreenToLocalTransform={this.childXf(childLayout)}
+ isContentActive={this.isChildContentActive}
+ isDocumentActive={this._props.childDocumentsActive?.() || this.Document._childDocumentsActive ? this._props.isDocumentActive : this.isContentActive}
+ hideResizeHandles={!!(childLayout.layout_fitWidth || this._props.childHideResizeHandles)}
+ hideDecorationTitle={this._props.childHideDecorationTitle}
+ fitContentsToBox={this._props.fitContentsToBox}
+ focus={this._props.focus}
+ childFilters={this.childDocFilters}
+ childFiltersByRanges={this.childDocRangeFilters}
+ searchFilterDocs={this.searchFilterDocs}
+ dontRegisterView={this._props.dontRegisterView}
+ addDocument={this._props.addDocument}
+ moveDocument={this._props.moveDocument}
+ removeDocument={this._props.removeDocument}
+ whenChildContentsActiveChanged={this._props.whenChildContentsActiveChanged}
+ addDocTab={this._props.addDocTab}
+ pinToPres={this._props.pinToPres}
+ dontCenter={StrCast(this.layoutDoc.layout_dontCenter) as 'y' | 'x' | 'xy'}
+ />
+ );
+
/**
* @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/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 05670562e..5803acca0 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -200,7 +200,7 @@ export class CollectionSchemaView extends CollectionSubView() {
this._props.setContentViewBox?.(this);
document.addEventListener('keydown', this.onKeyDown);
- Object.entries(this._documentOptions).forEach((pair: [string, FInfo]) => this.fieldInfos.set(pair[0], pair[1]));
+ Object.entries(this._documentOptions).forEach(pair => this.fieldInfos.set(pair[0], pair[1] as FInfo));
this._keysDisposer = observe(
this.dataDoc[this.fieldKey ?? 'data'] as List<Doc>,
change => {
diff --git a/src/client/views/collections/collectionSchema/SchemaCellField.tsx b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
index daffdf1f5..9ad94cb31 100644
--- a/src/client/views/collections/collectionSchema/SchemaCellField.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
@@ -85,6 +85,7 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
() => this._editing,
editing => {
if (editing) {
+ this.setContent((this._unrenderedContent = this._props.GetValue() ?? ''));
this.setupRefSelect(this.refSelectConditionMet);
} else {
this._overlayDisposer?.();
@@ -99,7 +100,7 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
() => this._props.GetValue(),
fieldVal => {
this._unrenderedContent = fieldVal ?? '';
- this.finalizeEdit(false, false, false);
+ this._editing && this.finalizeEdit(false, false, false);
}
);
}
diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index e6fe46638..173984dc7 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -32,6 +32,7 @@ import { FInfotoColType } from './CollectionSchemaView';
import './CollectionSchemaView.scss';
import { SchemaColumnHeader } from './SchemaColumnHeader';
import { SchemaCellField } from './SchemaCellField';
+import { DocLayout } from '../../../../fields/DocSymbols';
/**
* SchemaTableCells make up the majority of the visual representation of the SchemaView.
@@ -104,13 +105,14 @@ export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellPro
public static renderProps(props: SchemaTableCellProps) {
const { Doc: Document, fieldKey, /* getFinfo,*/ columnWidth, isRowActive } = props;
let protoCount = 0;
- let doc: Doc | undefined = Document;
+ const layoutDoc = fieldKey.startsWith('_') ? Document[DocLayout] : Document;
+ let doc = Document;
while (doc) {
if (Object.keys(doc).includes(fieldKey.replace(/^_/, ''))) break;
protoCount++;
doc = DocCast(doc.proto);
}
- const color = protoCount === 0 || (fieldKey.startsWith('_') && Document[fieldKey] === undefined) ? 'black' : 'blue'; // color of text in cells
+ const color = layoutDoc !== Document ? 'red' : protoCount === 0 || (fieldKey.startsWith('_') && Document[fieldKey] === undefined) ? 'black' : 'blue'; // color of text in cells
const textDecoration = '';
const fieldProps: FieldViewProps = {
childFilters: returnEmptyFilter,
@@ -130,7 +132,7 @@ export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellPro
focus: emptyFunction,
addDocTab: SchemaTableCell.addFieldDoc,
pinToPres: returnZero,
- Document: DocCast(Document.rootDocument, Document),
+ Document: Document,
fieldKey: fieldKey,
PanelWidth: columnWidth,
PanelHeight: props.rowHeight,
@@ -175,7 +177,8 @@ export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellPro
const inQuotes = (strField: string) => {
return (strField.startsWith('`') && strField.endsWith('`')) || (strField.startsWith("'") && strField.endsWith("'")) || (strField.startsWith('"') && strField.endsWith('"'));
};
- if (!inQuotes(this._submittedValue) && inQuotes(modField)) modField = modField.substring(1, modField.length - 1);
+ const submittedValue = this._submittedValue.startsWith(eqSymbol) ? this._submittedValue.slice(eqSymbol.length) : this._submittedValue;
+ if (!inQuotes(submittedValue) && inQuotes(modField)) modField = modField.substring(1, modField.length - 1);
return eqSymbol + modField;
};
@@ -211,8 +214,7 @@ export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellPro
this._props.finishEdit?.();
return true;
}
- const hasNoLayout = Doc.IsDataProto(fieldProps.Document) ? true : undefined; // the "delegate" is a a data document so never write to it's proto
- const ret = Doc.SetField(fieldProps.Document, this._props.fieldKey.replace(/^_/, ''), value, hasNoLayout);
+ const ret = Doc.SetField(fieldProps.Document, this._props.fieldKey, value);
this._submittedValue = value;
this._props.finishEdit?.();
return ret;