diff options
| author | eleanor-park <eleanor_park@brown.edu> | 2024-04-14 14:27:43 -0400 |
|---|---|---|
| committer | eleanor-park <eleanor_park@brown.edu> | 2024-04-14 14:27:43 -0400 |
| commit | 15e40cd865474f524c8e35f9352fc40d4b515ab3 (patch) | |
| tree | 4ba71fafec248b22226157908b9fb578e4529df6 /src/client/views/collections/collectionFreeForm | |
| parent | d938cd08650279f5c7894793d5fd78ec4068694c (diff) | |
| parent | 36d18da80e5e5e1c6cae0dc21c1677a7ab9c1d77 (diff) | |
Merge branch 'eleanor-starter' of https://github.com/brown-dash/Dash-Web into eleanor-starter
Diffstat (limited to 'src/client/views/collections/collectionFreeForm')
3 files changed, 49 insertions, 39 deletions
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoUI.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoUI.tsx index 8628ca3c3..43b877705 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoUI.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoUI.tsx @@ -34,7 +34,7 @@ export class CollectionFreeFormInfoUI extends ObservableReactComponent<Collectio set currState(val) { runInAction(() => (this._currState = val)); } // prettier-ignore componentWillUnmount(): void { - this._props.Freeform.layoutDoc.backgroundColor = this._originalbackground; + this._props.Freeform.dataDoc.backgroundColor = this._originalbackground; } setCurrState = (state: infoState) => { @@ -45,9 +45,9 @@ export class CollectionFreeFormInfoUI extends ObservableReactComponent<Collectio }; setupStates = () => { - this._originalbackground = StrCast(this._props.Freeform.layoutDoc.backgroundColor); + this._originalbackground = StrCast(this._props.Freeform.dataDoc.backgroundColor); // state entry functions - const setBackground = (colour: string) => () => (this._props.Freeform.layoutDoc.backgroundColor = colour); + const setBackground = (colour: string) => () => (this._props.Freeform.dataDoc.backgroundColor = colour); const setOpacity = (opacity: number) => () => (this._props.Freeform.layoutDoc.opacity = opacity); // arc transition trigger conditions const firstDoc = () => (this._props.Freeform.childDocs.length ? this._props.Freeform.childDocs[0] : undefined); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index ef4ab55db..2bf4f3c1e 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1,7 +1,7 @@ import { findSegment, intersect } from '@turf/turf'; import { Bezier } from 'bezier-js'; import { Colors } from 'browndash-components'; -import { action, computed, IReactionDisposer, makeObservable, observable, reaction, runInAction } from 'mobx'; +import { action, computed, IReactionDisposer, makeObservable, observable, reaction, runInAction, trace } from 'mobx'; import { observer } from 'mobx-react'; import { computedFn } from 'mobx-utils'; import * as React from 'react'; @@ -18,7 +18,7 @@ import { BoolCast, Cast, DocCast, NumCast, ScriptCast, StrCast } from '../../../ import { ImageField } from '../../../../fields/URLField'; import { TraceMobx } from '../../../../fields/util'; import { GestureUtils } from '../../../../pen-gestures/GestureUtils'; -import { aggregateBounds, DashColor, emptyFunction, intersectRect, lightOrDark, OmitKeys, returnFalse, returnZero, setupMoveUpEvents, Utils } from '../../../../Utils'; +import { aggregateBounds, DashColor, emptyFunction, intersectRect, lightOrDark, numberValue, OmitKeys, returnFalse, returnZero, setupMoveUpEvents, Utils } from '../../../../Utils'; import { CognitiveServices } from '../../../cognitive_services/CognitiveServices'; import { Docs, DocUtils } from '../../../documents/Documents'; import { CollectionViewType, DocumentType } from '../../../documents/DocumentTypes'; @@ -31,14 +31,14 @@ import { SelectionManager } from '../../../util/SelectionManager'; import { freeformScrollMode } from '../../../util/SettingsManager'; import { SnappingManager } from '../../../util/SnappingManager'; import { Transform } from '../../../util/Transform'; -import { undoBatch, UndoManager } from '../../../util/UndoManager'; +import { undoable, undoBatch, UndoManager } from '../../../util/UndoManager'; import { Timeline } from '../../animationtimeline/Timeline'; import { ContextMenu } from '../../ContextMenu'; import { GestureOverlay } from '../../GestureOverlay'; import { CtrlKey } from '../../GlobalKeyHandler'; import { ActiveInkWidth, InkingStroke, SetActiveInkColor, SetActiveInkWidth } from '../../InkingStroke'; import { LightboxView } from '../../LightboxView'; -import { CollectionFreeFormDocumentView, CollectionFreeFormDocumentViewWrapper } from '../../nodes/CollectionFreeFormDocumentView'; +import { CollectionFreeFormDocumentView } from '../../nodes/CollectionFreeFormDocumentView'; import { SchemaCSVPopUp } from '../../nodes/DataVizBox/SchemaCSVPopUp'; import { DocumentView, OpenWhere } from '../../nodes/DocumentView'; import { FieldViewProps, FocusViewOptions } from '../../nodes/FieldView'; @@ -160,8 +160,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection ? { x: cb[0], y: cb[1], r: cb[2], b: cb[3] } : aggregateBounds( this._layoutElements.filter(e => e.bounds?.width && !e.bounds.z).map(e => e.bounds!), - NumCast(this.layoutDoc._xPadding, 10), - NumCast(this.layoutDoc._yPadding, 10) + NumCast(this.layoutDoc._xPadding, this._props.xPadding ?? 10), + NumCast(this.layoutDoc._yPadding, this._props.yPadding ?? 10) ); } @computed get nativeWidth() { @@ -463,7 +463,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection const eles = this.childLayoutPairs.map(pair => pair.layout).filter(cd => (this.Document._freeform_useClusters ? NumCast(cd.layout_cluster) : NumCast(cd.group, -1)) === cluster); const clusterDocs = eles.map(ele => DocumentManager.Instance.getDocumentView(ele, this.DocumentView?.())!); const { left, top } = clusterDocs[0].getBounds || { left: 0, top: 0 }; - const de = new DragManager.DocumentDragData(eles, e.ctrlKey || e.altKey ? 'embed' : undefined); + const de = new DragManager.DocumentDragData(eles, e.ctrlKey || e.altKey ? dropActionType.embed : undefined); de.moveDocument = this._props.moveDocument; de.offset = this.screenToFreeformContentsXf.transformDirection(ptsParent.clientX - left, ptsParent.clientY - top); DragManager.StartDocumentDrag( @@ -784,7 +784,6 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection this.onGesture(e, new GestureUtils.GestureEvent(gesture, points, GestureOverlay.getBounds(points), text)); }; - @action onPointerMove = (e: PointerEvent) => { if (this.tryDragCluster(e, this._hitCluster)) { e.stopPropagation(); // we're moving a cluster, so stop propagation and return true to end panning and let the document drag take over @@ -1357,23 +1356,29 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection isContentActive = () => this._props.isContentActive(); - @undoBatch + /** + * Create a new text note of the same style as the one being typed into. + * If the text doc is be part of a larger templated doc, the new Doc will be a copy of the templated Doc + * + * @param fieldProps render props for the text doc being typed into + * @param below whether to place the new text Doc below or to the right of the one being typed into. + * @returns whether the new text doc was created and added successfully + */ + createTextDocCopy = undoable((fieldProps: FieldViewProps, below: boolean) => { + const textDoc = DocCast(fieldProps.Document.rootDocument, fieldProps.Document); + const newDoc = Doc.MakeCopy(textDoc, true); + newDoc[DocData][Doc.LayoutFieldKey(newDoc, fieldProps.LayoutTemplateString)] = undefined; // the copy should not copy the text contents of it source, just the render style + newDoc.x = NumCast(textDoc.x) + (below ? 0 : NumCast(textDoc._width) + 10); + newDoc.y = NumCast(textDoc.y) + (below ? NumCast(textDoc._height) + 10 : 0); + FormattedTextBox.SetSelectOnLoad(newDoc); + FormattedTextBox.DontSelectInitialText = true; + return this.addDocument?.(newDoc); + }, 'copied text note'); + onKeyDown = (e: React.KeyboardEvent, fieldProps: FieldViewProps) => { if ((e.metaKey || e.ctrlKey || e.altKey || fieldProps.Document._createDocOnCR) && ['Tab', 'Enter'].includes(e.key)) { e.stopPropagation?.(); - const below = !e.altKey && e.key !== 'Tab'; - const layout_fieldKey = StrCast(fieldProps.fieldKey); - const newDoc = Doc.MakeCopy(fieldProps.Document, true); - const dataField = fieldProps.Document[Doc.LayoutFieldKey(newDoc)]; - newDoc[DocData][Doc.LayoutFieldKey(newDoc)] = dataField === undefined || Cast(dataField, listSpec(Doc), null)?.length !== undefined ? new List<Doc>([]) : undefined; - if (below) newDoc.y = NumCast(fieldProps.Document.y) + NumCast(fieldProps.Document._height) + 10; - else newDoc.x = NumCast(fieldProps.Document.x) + NumCast(fieldProps.Document._width) + 10; - if (layout_fieldKey !== 'layout' && fieldProps.Document[layout_fieldKey] instanceof Doc) { - newDoc[layout_fieldKey] = fieldProps.Document[layout_fieldKey]; - } - newDoc[DocData].text = undefined; - FormattedTextBox.SetSelectOnLoad(newDoc); - return this.addDocument?.(newDoc); + return this.createTextDocCopy(fieldProps, !e.altKey && e.key !== 'Tab'); } }; @computed get childPointerEvents() { @@ -1395,7 +1400,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection const childLayout = entry.pair.layout; const childData = entry.pair.data; return ( - <CollectionFreeFormDocumentViewWrapper + <CollectionFreeFormDocumentView {...OmitKeys(entry, ['replica', 'pair']).omit} key={childLayout[Id] + (entry.replica || '')} Document={childLayout} @@ -1558,7 +1563,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection renderCutoffProvider = computedFn( function renderCutoffProvider(this: any, doc: Doc) { - return !this._renderCutoffData.get(doc[Id] + ''); + return this.Document.isTemplateDoc ? false : !this._renderCutoffData.get(doc[Id] + ''); }.bind(this) ); @@ -1681,7 +1686,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection if (!code.includes('dashDiv')) { const script = CompileScript(code, { params: { docView: 'any' }, typecheck: false, editable: true }); if (script.compiled) script.run({ this: this.DocumentView?.() }); - } else code && !first && eval(code); + } else code && !first && eval?.(code); }, { fireImmediately: true } ); @@ -1862,7 +1867,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection !this._props.isAnnotationOverlay && !Doc.noviceMode && optionItems.push({ description: (this._showAnimTimeline ? 'Close' : 'Open') + ' Animation Timeline', event: action(() => (this._showAnimTimeline = !this._showAnimTimeline)), icon: 'eye' }); - this._props.renderDepth && optionItems.push({ description: 'Use Background Color as Default', event: () => (Cast(Doc.UserDoc().emptyCollection, Doc, null)._backgroundColor = StrCast(this.layoutDoc._backgroundColor)), icon: 'palette' }); + this._props.renderDepth && optionItems.push({ description: 'Use Background Color as Default', event: () => (Cast(Doc.UserDoc().emptyCollection, Doc, null).backgroundColor = StrCast(this.layoutDoc.backgroundColor)), icon: 'palette' }); this._props.renderDepth && optionItems.push({ description: 'Fit Content Once', event: this.fitContentOnce, icon: 'object-group' }); if (!Doc.noviceMode) { optionItems.push({ description: (!Doc.NativeWidth(this.layoutDoc) || !Doc.NativeHeight(this.layoutDoc) ? 'Freeze' : 'Unfreeze') + ' Aspect', event: this.toggleNativeDimensions, icon: 'snowflake' }); @@ -1926,7 +1931,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection incrementalRender = action(() => { if (!LightboxView.LightboxDoc || LightboxView.Contains(this.DocumentView?.())) { const layout_unrendered = this.childDocs.filter(doc => !this._renderCutoffData.get(doc[Id])); - const loadIncrement = 5; + const loadIncrement = this.Document.isTemplateDoc ? Number.MAX_VALUE : 5; for (var i = 0; i < Math.min(layout_unrendered.length, loadIncrement); i++) { this._renderCutoffData.set(layout_unrendered[i][Id] + '', true); } @@ -2162,6 +2167,7 @@ ScriptingGlobals.add(function sendToBack(doc: Doc) { SelectionManager.Views.forEach(view => view.CollectionFreeFormView?.bringToFront(view.Document, true)); }); ScriptingGlobals.add(function datavizFromSchema(doc: Doc) { + // creating a dataviz doc to represent the schema table SelectionManager.Views.forEach(view => { if (!view.layoutDoc.schema_columnKeys) { view.layoutDoc.schema_columnKeys = new List<string>(['title', 'type', 'author', 'author_date']); @@ -2175,22 +2181,22 @@ ScriptingGlobals.add(function datavizFromSchema(doc: Doc) { for (let i = 0; i < children.length; i++) { let eachRow = []; for (let j = 0; j < keys.length; j++) { - var cell = children[i][keys[j]]; - if (cell && (cell as string)) cell = cell.toString().replace(/\,/g, ''); + var cell = children[i][keys[j]]?.toString(); + if (cell) cell = cell.toString().replace(/\,/g, ''); eachRow.push(cell); } csvRows.push(eachRow); } const blob = new Blob([csvRows.join('\n')], { type: 'text/csv' }); - const options = { x: 0, y: -300, title: 'schemaTable', _width: 300, _height: 100, type: 'text/csv' }; + const options = { x: 0, y: 0, title: 'schemaTable', _width: 300, _height: 100, type: 'text/csv' }; const file = new File([blob], 'schemaTable', options); const loading = Docs.Create.LoadingDocument(file, options); loading.presentation_openInLightbox = true; DocUtils.uploadFileToDoc(file, {}, loading); + // holds the doc in a popup until it is dragged onto a canvas if (view.ComponentView?.addDocument) { - // loading.dataViz_fromSchema = true; - loading.dataViz_asSchema = view.layoutDoc; + loading._dataViz_asSchema = view.layoutDoc; SchemaCSVPopUp.Instance.setView(view); SchemaCSVPopUp.Instance.setTarget(view.layoutDoc); SchemaCSVPopUp.Instance.setDataVizDoc(loading); diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index a417d777a..b913e05ad 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -178,7 +178,7 @@ export class MarqueeView extends ObservableReactComponent<SubCollectionViewProps } else if (!e.ctrlKey && !e.metaKey && SelectionManager.Views.length < 2) { FormattedTextBox.SelectOnLoadChar = Doc.UserDoc().defaultTextLayout && !this._props.childLayoutString ? e.key : ''; FormattedTextBox.LiveTextUndo = UndoManager.StartBatch('type new note'); - this._props.addLiveTextDocument(DocUtils.GetNewTextDoc('-typed text-', x, y, 200, 100, this._props.xPadding === 0)); + this._props.addLiveTextDocument(DocUtils.GetNewTextDoc('-typed text-', x, y, 200, 100)); e.stopPropagation(); } }; @@ -494,7 +494,6 @@ export class MarqueeView extends ObservableReactComponent<SubCollectionViewProps followLinkToggle: true, _width: 200, _height: 200, - _layout_fitContentsToBox: true, _layout_showSidebar: true, title: 'overview', }); @@ -635,8 +634,13 @@ export class MarqueeView extends ObservableReactComponent<SubCollectionViewProps } MarqueeRef: HTMLDivElement | null = null; + /** + * This is called for every drag movement when a document is dragged over this collection. + * If the document is dragged within 25 pixels of the edge of the collection and paused, this will + * auto scroll the collection so that it can be dragged farther (unless auto panning has been disabled) + */ @action - onDragAutoScroll = (e: CustomEvent<React.DragEvent>) => { + onDragMovePause = (e: CustomEvent<React.DragEvent>) => { if ((e as any).handlePan || this._props.isAnnotationOverlay) return; (e as any).handlePan = true; @@ -659,7 +663,7 @@ export class MarqueeView extends ObservableReactComponent<SubCollectionViewProps <div className="marqueeView" ref={r => { - r?.addEventListener('dashDragAutoScroll', this.onDragAutoScroll as any); + r?.addEventListener('dashDragMovePause', this.onDragMovePause as any); this.MarqueeRef = r; }} style={{ |
