diff options
| author | bobzel <zzzman@gmail.com> | 2023-08-27 12:14:02 -0400 |
|---|---|---|
| committer | bobzel <zzzman@gmail.com> | 2023-08-27 12:14:02 -0400 |
| commit | 2bf684f3f7960b92fb052d746cb25c11b603b190 (patch) | |
| tree | 742aff58e4f0879574bc5cd1ce3935208c30209e /src/client/views/collections | |
| parent | 68ddebab45946697270c5f291ff9fdd044b6e83d (diff) | |
| parent | bf1777b93be0707e17e3b3c0ca6c965facebfe14 (diff) | |
Merge branch 'master' into secondpropertiesmenu-emily
Diffstat (limited to 'src/client/views/collections')
14 files changed, 203 insertions, 164 deletions
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 0052c4196..e15d57306 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -498,6 +498,7 @@ export class CollectionDockingView extends CollectionSubView() { _layout_fitWidth: true, title: `Untitled Tab ${NumCast(dashboard['pane-count'])}`, }); + Doc.AddDocToList(Doc.MyHeaderBar, 'data', docToAdd); inheritParentAcls(this.rootDoc, docToAdd, false); CollectionDockingView.AddSplit(docToAdd, OpenWhereMod.none, stack); } @@ -541,6 +542,7 @@ export class CollectionDockingView extends CollectionSubView() { _freeform_backgroundGrid: true, title: `Untitled Tab ${NumCast(dashboard['pane-count'])}`, }); + Doc.AddDocToList(Doc.MyHeaderBar, 'data', docToAdd); inheritParentAcls(this.dataDoc, docToAdd, false); CollectionDockingView.AddSplit(docToAdd, OpenWhereMod.none, stack); } @@ -549,7 +551,7 @@ export class CollectionDockingView extends CollectionSubView() { }; render() { - const href = ImageCast(this.rootDoc.thumb)?.url.href; + const href = ImageCast(this.rootDoc.thumb)?.url?.href; return this.props.renderDepth > -1 ? ( <div> {href ? ( diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx index ad84d859d..de58e1fe7 100644 --- a/src/client/views/collections/CollectionStackedTimeline.tsx +++ b/src/client/views/collections/CollectionStackedTimeline.tsx @@ -716,7 +716,7 @@ class StackedTimelineAnchor extends React.Component<StackedTimelineAnchorProps> this._disposer = reaction( () => this.props.currentTimecode(), time => { - const dictationDoc = Cast(this.props.layoutDoc['data-dictation'], Doc, null); + const dictationDoc = Cast(this.props.layoutDoc.data_dictation, Doc, null); const isDictation = dictationDoc && LinkManager.Links(this.props.mark).some(link => Cast(link.link_anchor_1, Doc, null)?.annotationOn === dictationDoc); if ( !LightboxView.LightboxDoc && diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index c189ef126..eb4685834 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -298,7 +298,11 @@ export function CollectionSubView<X>(moreProps?: X) { let source = split; if (split.startsWith('data:image') && split.includes('base64')) { const [{ accessPaths }] = await Networking.PostToServer('/uploadRemoteImage', { sources: [split] }); - source = Utils.prepend(accessPaths.agnostic.client); + if (accessPaths.agnostic.client.indexOf("dashblobstore") === -1) { + source = Utils.prepend(accessPaths.agnostic.client); + } else { + source = accessPaths.agnostic.client; + } } if (source.startsWith('http')) { const doc = Docs.Create.ImageDocument(source, { ...options, _width: 300 }); diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx index 192d48c64..a8f5345b7 100644 --- a/src/client/views/collections/CollectionTimeView.tsx +++ b/src/client/views/collections/CollectionTimeView.tsx @@ -65,9 +65,9 @@ export class CollectionTimeView extends CollectionSubView() { @action scrollPreview = (docView: DocumentView, anchor: Doc, focusSpeed: number, options: DocFocusOptions) => { // if in preview, then override document's fields with view spec - this._focusFilters = StrListCast(anchor.presDocFilters); - this._focusRangeFilters = StrListCast(anchor.presPinDocRangeFilters); - this._focusPivotField = StrCast(anchor.presPivotField); + this._focusFilters = StrListCast(anchor.config_docFilters); + this._focusRangeFilters = StrListCast(anchor.config_docRangeFilters); + this._focusPivotField = StrCast(anchor.config_pivotField); return undefined; }; diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index ea3b5065f..eed04b3ee 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -66,17 +66,17 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree return this.props.DataDoc || this.doc; } @computed get treeViewtruncateTitleWidth() { - return NumCast(this.doc.treeViewTruncateTitleWidth, this.panelWidth()); + return NumCast(this.doc.treeView_TruncateTitleWidth, this.panelWidth()); } @computed get treeChildren() { TraceMobx(); return this.props.childDocuments || this.childDocs; } @computed get outlineMode() { - return this.doc.treeViewType === TreeViewType.outline; + return this.doc.treeView_Type === TreeViewType.outline; } @computed get fileSysMode() { - return this.doc.treeViewType === TreeViewType.fileSystem; + return this.doc.treeView_Type === TreeViewType.fileSystem; } @computed get dashboardMode() { return this.doc === Doc.MyDashboards; @@ -191,9 +191,9 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree // need to test if propagation has stopped because GoldenLayout forces a parallel react hierarchy to be created for its top-level layout if (!Doc.noviceMode) { const layoutItems: ContextMenuProps[] = []; - layoutItems.push({ description: 'Make tree state ' + (this.doc.treeViewOpenIsTransient ? 'persistent' : 'transient'), event: () => (this.doc.treeViewOpenIsTransient = !this.doc.treeViewOpenIsTransient), icon: 'paint-brush' }); - layoutItems.push({ description: (this.doc.treeViewHideHeaderFields ? 'Show' : 'Hide') + ' Header Fields', event: () => (this.doc.treeViewHideHeaderFields = !this.doc.treeViewHideHeaderFields), icon: 'paint-brush' }); - layoutItems.push({ description: (this.doc.treeViewHideTitle ? 'Show' : 'Hide') + ' Title', event: () => (this.doc.treeViewHideTitle = !this.doc.treeViewHideTitle), icon: 'paint-brush' }); + layoutItems.push({ description: 'Make tree state ' + (this.doc.treeView_OpenIsTransient ? 'persistent' : 'transient'), event: () => (this.doc.treeView_OpenIsTransient = !this.doc.treeView_OpenIsTransient), icon: 'paint-brush' }); + layoutItems.push({ description: (this.doc.treeView_HideHeaderFields ? 'Show' : 'Hide') + ' Header Fields', event: () => (this.doc.treeView_HideHeaderFields = !this.doc.treeView_HideHeaderFields), icon: 'paint-brush' }); + layoutItems.push({ description: (this.doc.treeView_HideTitle ? 'Show' : 'Hide') + ' Title', event: () => (this.doc.treeView_HideTitle = !this.doc.treeView_HideTitle), icon: 'paint-brush' }); ContextMenu.Instance.addItem({ description: 'Options...', subitems: layoutItems, icon: 'eye' }); const existingOnClick = ContextMenu.Instance.findByDescription('OnClick...'); const onClicks: ContextMenuProps[] = existingOnClick && 'subitems' in existingOnClick ? existingOnClick.subitems : []; @@ -215,7 +215,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree height={'auto'} GetValue={() => StrCast(this.dataDoc.title)} SetValue={undoBatch((value: string, shift: boolean, enter: boolean) => { - if (enter && this.props.Document.treeViewType === TreeViewType.outline) this.makeTextCollection(this.treeChildren); + if (enter && this.props.Document.treeView_Type === TreeViewType.outline) this.makeTextCollection(this.treeChildren); this.dataDoc.title = value; return true; })} @@ -261,7 +261,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree const icons = StrListCast(this.doc.childContextMenuIcons); return StrListCast(this.doc.childContextMenuLabels).map((label, i) => ({ script: customScripts[i], filter: customFilters[i], icon: icons[i], label })); }; - headerFields = () => this.props.treeViewHideHeaderFields || BoolCast(this.doc.treeViewHideHeaderFields); + headerFields = () => this.props.treeViewHideHeaderFields || BoolCast(this.doc.treeView_HideHeaderFields); @observable _renderCount = 1; @computed get treeViewElements() { TraceMobx(); @@ -389,7 +389,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree const background = () => this.props.styleProvider?.(this.doc, this.props, StyleProp.BackgroundColor); const color = () => this.props.styleProvider?.(this.doc, this.props, StyleProp.Color); const pointerEvents = () => (this.props.isContentActive() === false ? 'none' : undefined); - const titleBar = this.props.treeViewHideTitle || this.doc.treeViewHideTitle ? null : this.titleBar; + const titleBar = this.props.treeViewHideTitle || this.doc.treeView_HideTitle ? null : this.titleBar; return ( <div style={{ display: 'flex', flexDirection: 'column', height: '100%', pointerEvents: 'all' }}> {!this.buttonMenu && !this.noviceExplainer ? null : ( @@ -401,7 +401,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree <div className="collectionTreeView-contents" key="tree" - ref={r => !this.doc.treeViewHasOverlay && r && this.createTreeDropTarget(r)} + ref={r => !this.doc.treeView_HasOverlay && r && this.createTreeDropTarget(r)} style={{ ...(!titleBar ? { marginLeft: this.marginX(), paddingTop: this.marginTop() } : {}), color: color(), @@ -426,6 +426,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree minHeight: '100%', }} onWheel={e => e.stopPropagation()} + onClick={e => (!this.layoutDoc.forceActive ? this.props.select(false) : SelectionManager.DeselectAll())} onDrop={this.onTreeDrop}> <ul className={`no-indent${this.outlineMode ? '-outline' : ''}`}>{this.treeViewElements}</ul> </div> @@ -440,7 +441,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree const scale = (this.props.NativeDimScaling?.() || 1) * NumCast(this.layoutDoc._freeform_scale, 1) || 1; return ( <div style={{ transform: `scale(${scale})`, transformOrigin: 'top left', width: `${100 / scale}%`, height: `${100 / scale}%` }}> - {!(this.doc instanceof Doc) || !this.treeChildren ? null : this.doc.treeViewHasOverlay ? ( + {!(this.doc instanceof Doc) || !this.treeChildren ? null : this.doc.treeView_HasOverlay ? ( <CollectionFreeFormView {...this.props} setContentView={emptyFunction} diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index c33519afb..88f892efc 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -41,7 +41,7 @@ interface CollectionViewProps_ extends FieldViewProps { isAnnotationOverlayScrollable?: boolean; // whether the annotation overlay can be vertically scrolled (just for tree views, currently) layoutEngine?: () => string; setPreviewCursor?: (func: (x: number, y: number, drag: boolean, hide: boolean) => void) => void; - setBrushViewer?: (func?: (view: { width: number; height: number; panX: number; panY: number }) => void) => void; + setBrushViewer?: (func?: (view: { width: number; height: number; panX: number; panY: number }, transTime: number) => void) => void; ignoreUnrendered?: boolean; // property overrides for child documents diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index d787f5262..f379d09ff 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -137,7 +137,11 @@ export class TabDocView extends React.Component<TabDocViewProps> { setupMoveUpEvents( this, e, - e => !e.defaultPrevented && DragManager.StartDocumentDrag([iconWrap], new DragManager.DocumentDragData([doc], doc.dropAction as dropActionType), e.clientX, e.clientY), + e => + !e.defaultPrevented && + DragManager.StartDocumentDrag([iconWrap], new DragManager.DocumentDragData([doc], doc.dropAction as dropActionType), e.clientX, e.clientY, undefined, () => { + CollectionDockingView.CloseSplit(doc); + }), returnFalse, action(e => { if (this.view) { @@ -256,46 +260,47 @@ export class TabDocView extends React.Component<TabDocViewProps> { return; } const anchorDoc = DocumentManager.Instance.getDocumentView(doc)?.ComponentView?.getAnchor?.(false, pinProps); - const pinDoc = Doc.MakeDelegate(anchorDoc && anchorDoc !== doc ? anchorDoc : doc); - pinDoc.presentationTargetDoc = anchorDoc ?? doc; + const pinDoc = anchorDoc?.type === DocumentType.CONFIG ? anchorDoc : Doc.MakeDelegate(anchorDoc && anchorDoc !== doc ? anchorDoc : doc); + pinDoc.presentation_targetDoc = anchorDoc ?? doc; pinDoc.title = doc.title + ' - Slide'; pinDoc.data = new List<Doc>(); // the children of the embedding's layout are the presentation slide children. the embedding's data field might be children of a collection, PDF data, etc -- in any case we don't want the tree view to "see" this data - pinDoc.presMovement = doc.type === DocumentType.SCRIPTING || pinProps?.pinDocLayout ? PresMovement.None : PresMovement.Zoom; - pinDoc.presDuration = pinDoc.presDuration ?? 1000; - pinDoc.groupWithUp = false; + pinDoc.presentation_movement = doc.type === DocumentType.SCRIPTING || pinProps?.pinDocLayout ? PresMovement.None : PresMovement.Zoom; + pinDoc.presentation_duration = pinDoc.presentation_duration ?? 1000; + pinDoc.presentation_groupWithUp = false; Doc.SetContainer(pinDoc, curPres); // these should potentially all be props passed down by the CollectionTreeView to the TreeView elements. That way the PresBox could configure all of its children at render time - pinDoc.treeViewRenderAsBulletHeader = true; // forces a tree view to render the document next to the bullet in the header area - pinDoc.treeViewHeaderWidth = '100%'; // forces the header to grow to be the same size as its largest sibling. - pinDoc.treeViewChildrenOnRoot = true; // tree view will look for hierarchical children on the root doc, not the data doc. - pinDoc.treeViewFieldKey = 'data'; // tree view will treat the 'data' field as the field where the hierarchical children are located instead of using the document's layout string field - pinDoc.treeViewExpandedView = 'data'; // in case the data doc has an expandedView set, this will mask that field and use the 'data' field when expanding the tree view - pinDoc.treeViewHideHeaderIfTemplate = true; // this will force the document to render itself as the tree view header + pinDoc.treeView = ''; // not really needed, but makes key value pane look better + pinDoc.treeView_RenderAsBulletHeader = true; // forces a tree view to render the document next to the bullet in the header area + pinDoc.treeView_HeaderWidth = '100%'; // forces the header to grow to be the same size as its largest sibling. + pinDoc.treeView_ChildrenOnRoot = true; // tree view will look for hierarchical children on the root doc, not the data doc. + pinDoc.treeView_FieldKey = 'data'; // tree view will treat the 'data' field as the field where the hierarchical children are located instead of using the document's layout string field + pinDoc.treeView_ExpandedView = 'data'; // in case the data doc has an expandedView set, this will mask that field and use the 'data' field when expanding the tree view + pinDoc.treeView_HideHeaderIfTemplate = true; // this will force the document to render itself as the tree view header const duration = NumCast(doc[`${Doc.LayoutFieldKey(pinDoc)}_duration`], null); if (pinProps.pinViewport) PresBox.pinDocView(pinDoc, pinProps, anchorDoc ?? doc); if (!pinProps?.audioRange && duration !== undefined) { pinDoc.mediaStart = 'manual'; pinDoc.mediaStop = 'manual'; - pinDoc.presStartTime = NumCast(doc.clipStart); - pinDoc.presEndTime = NumCast(doc.clipEnd, duration); + pinDoc.config_clipStart = NumCast(doc.clipStart); + pinDoc.config_clipEnd = NumCast(doc.clipEnd, duration); } if (pinProps?.activeFrame !== undefined) { - pinDoc.presActiveFrame = pinProps?.activeFrame; + pinDoc.config_activeFrame = pinProps?.activeFrame; pinDoc.title = doc.title + ' (move)'; - pinDoc.presMovement = PresMovement.Pan; + pinDoc.presentation_movement = PresMovement.Pan; } if (pinProps?.currentFrame !== undefined) { - pinDoc.presCurrentFrame = pinProps?.currentFrame; + pinDoc.config_currentFrame = pinProps?.currentFrame; pinDoc.title = doc.title + ' (move)'; - pinDoc.presMovement = PresMovement.Pan; + pinDoc.presentation_movement = PresMovement.Pan; } if (pinDoc.stroke_isInkMask) { - pinDoc.presHideAfter = true; - pinDoc.presHideBefore = true; - pinDoc.presMovement = PresMovement.None; + pinDoc.presentation_hideAfter = true; + pinDoc.presentation_hideBefore = true; + pinDoc.presentation_movement = PresMovement.None; } - if (curPres.expandBoolean) pinDoc.presExpandInlineButton = true; + if (curPres.expandBoolean) pinDoc.presentation_expandInlineButton = true; Doc.AddDocToList(curPres, 'data', pinDoc, PresBox.Instance?.sortArray()?.lastElement()); PresBox.Instance?.clearSelectedArray(); pinDoc && PresBox.Instance?.addToSelectedArray(pinDoc); //Update selected array @@ -393,7 +398,7 @@ export class TabDocView extends React.Component<TabDocViewProps> { }; getCurrentFrame = () => { - return NumCast(Cast(PresBox.Instance.activeItem.presentationTargetDoc, Doc, null)._currentFrame); + return NumCast(Cast(PresBox.Instance.activeItem.presentation_targetDoc, Doc, null)._currentFrame); }; static Activate = (tabDoc: Doc) => { const tab = Array.from(CollectionDockingView.Instance?.tabMap!).find(tab => tab.DashDoc === tabDoc && !tab.contentItem.config.props.keyValue); diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index 25a547066..3402a8c8d 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -78,17 +78,17 @@ const treeBulletWidth = function () { }; export enum TreeSort { - Up = 'up', - Down = 'down', - Zindex = 'z', - None = 'none', + AlphaUp = 'alphabetical from z', + AlphaDown = 'alphabetical from A', + Zindex = 'by Z index', + WhenAdded = 'when added', } /** * Renders a treeView of a collection of documents * * special fields: - * treeViewOpen : flag denoting whether the documents sub-tree (contents) is visible or hidden - * treeViewExpandedView : name of field whose contents are being displayed as the document's subtree + * treeView_Open : flag denoting whether the documents sub-tree (contents) is visible or hidden + * treeView_ExpandedView : name of field whose contents are being displayed as the document's subtree */ @observer export class TreeView extends React.Component<TreeViewProps> { @@ -104,16 +104,16 @@ export class TreeView extends React.Component<TreeViewProps> { private _treedropDisposer?: DragManager.DragDropDisposer; get treeViewOpenIsTransient() { - return this.props.treeView.doc.treeViewOpenIsTransient || Doc.IsDataProto(this.doc); + return this.props.treeView.doc.treeView_OpenIsTransient || Doc.IsDataProto(this.doc); } set treeViewOpen(c: boolean) { if (this.treeViewOpenIsTransient) this._transientOpenState = c; else { - this.doc.treeViewOpen = c; + this.doc.treeView_Open = c; this._transientOpenState = false; } } - @observable _transientOpenState = false; // override of the treeViewOpen field allowing the display state to be independent of the document's state + @observable _transientOpenState = false; // override of the treeView_Open field allowing the display state to be independent of the document's state @observable _editTitle: boolean = false; @observable _dref: DocumentView | undefined | null; get displayName() { @@ -132,29 +132,29 @@ export class TreeView extends React.Component<TreeViewProps> { ? this.fieldKey : Doc.noviceMode ? 'layout' - : StrCast(this.props.treeView.doc.treeViewExpandedView, 'fields'); + : StrCast(this.props.treeView.doc.treeView_ExpandedView, 'fields'); } @computed get doc() { return this.props.document; } @computed get treeViewOpen() { - return (!this.treeViewOpenIsTransient && Doc.GetT(this.doc, 'treeViewOpen', 'boolean', true)) || this._transientOpenState; + return (!this.treeViewOpenIsTransient && Doc.GetT(this.doc, 'treeView_Open', 'boolean', true)) || this._transientOpenState; } @computed get treeViewExpandedView() { - return this.validExpandViewTypes.includes(StrCast(this.doc.treeViewExpandedView)) ? StrCast(this.doc.treeViewExpandedView) : this.defaultExpandedView; + return this.validExpandViewTypes.includes(StrCast(this.doc.treeView_ExpandedView)) ? StrCast(this.doc.treeView_ExpandedView) : this.defaultExpandedView; } @computed get MAX_EMBED_HEIGHT() { return NumCast(this.props.treeViewParent.maxEmbedHeight, 200); } @computed get dataDoc() { - return this.props.document.treeViewChildrenOnRoot ? this.doc : this.doc[DocData]; + return this.props.document.treeView_ChildrenOnRoot ? this.doc : this.doc[DocData]; } @computed get layoutDoc() { return Doc.Layout(this.doc); } @computed get fieldKey() { - return StrCast(this.doc._treeViewFieldKey, Doc.LayoutFieldKey(this.doc)); + return StrCast(this.doc._treeView_FieldKey, Doc.LayoutFieldKey(this.doc)); } @computed get childDocs() { return this.childDocList(this.fieldKey); @@ -308,13 +308,13 @@ export class TreeView extends React.Component<TreeViewProps> { const bullet = Docs.Create.TextDocument('', { layout: CollectionView.LayoutString('data'), title: '-title-', - treeViewExpandedViewLock: true, - treeViewExpandedView: 'data', + treeView_ExpandedViewLock: true, + treeView_ExpandedView: 'data', _type_collection: CollectionViewType.Tree, layout_hideLinkButton: true, _layout_showSidebar: true, _layout_fitWidth: true, - treeViewType: TreeViewType.outline, + treeView_Type: TreeViewType.outline, x: 0, y: 0, _xMargin: 0, @@ -395,7 +395,7 @@ export class TreeView extends React.Component<TreeViewProps> { }; const addDoc = inside ? localAdd : parentAddDoc; const move = (!dropAction || dropAction === 'proto' || dropAction === 'move' || dropAction === 'same') && moveDocument; - const canAdd = (!this.props.treeView.outlineMode && !StrCast((inside ? this.props.document : this.props.treeViewParent)?.treeViewFreezeChildren).includes('add')) || forceAdd; + const canAdd = (!this.props.treeView.outlineMode && !StrCast((inside ? this.props.document : this.props.treeViewParent)?.treeView_FreezeChildren).includes('add')) || forceAdd; if (canAdd) { this.props.parentTreeView instanceof TreeView && (this.props.parentTreeView.dropping = true); const res = droppedDocuments.reduce((added, d) => (move ? move(d, undefined, addDoc) || (dropAction === 'proto' ? addDoc(d) : false) : addDoc(d)) || added, false); @@ -438,7 +438,7 @@ export class TreeView extends React.Component<TreeViewProps> { doc && Object.keys(doc).forEach(key => !(key in ids) && doc[key] !== ComputedField.undefined && (ids[key] = key)); for (const key of Object.keys(ids).slice().sort()) { - if (this.props.skipFields?.includes(key) || key === 'title' || key === 'treeViewOpen') continue; + if (this.props.skipFields?.includes(key) || key === 'title' || key === 'treeView_Open') continue; const contents = doc[key]; let contentElement: (JSX.Element | null)[] | JSX.Element = []; @@ -538,7 +538,7 @@ export class TreeView extends React.Component<TreeViewProps> { const expandKey = this.treeViewExpandedView; const sortings = (this.props.styleProvider?.(this.doc, this.props.treeView.props, StyleProp.TreeViewSortings) as { [key: string]: { color: string; icon: JSX.Element | string } }) ?? {}; if (['links', 'annotations', 'embeddings', this.fieldKey].includes(expandKey)) { - const sorting = StrCast(this.doc.treeViewSortCriterion, TreeSort.None); + const sorting = StrCast(this.doc.treeView_SortCriterion, TreeSort.WhenAdded); const sortKeys = Object.keys(sortings); const curSortIndex = Math.max( 0, @@ -550,7 +550,7 @@ export class TreeView extends React.Component<TreeViewProps> { const localAdd = (doc: Doc, addBefore?: Doc, before?: boolean) => { // if there's a sort ordering specified that can be modified on drop (eg, zorder can be modified, alphabetical can't), // then the modification would be done here - const ordering = StrCast(this.doc.treeViewSortCriterion); + const ordering = StrCast(this.doc.treeView_SortCriterion); if (ordering === TreeSort.Zindex) { const docs = TreeView.sortDocs(this.childDocs || ([] as Doc[]), ordering); doc.zIndex = addBefore ? NumCast(addBefore.zIndex) + (before ? -0.5 : 0.5) : 1000; @@ -578,10 +578,11 @@ export class TreeView extends React.Component<TreeViewProps> { return ( <div> {!docs?.length || this.props.AddToMap /* hack to identify pres box trees */ ? null : ( - <div className={'treeView-sorting'}> + <div className='treeView-sorting'> <IconButton color={sortings[sorting]?.color} size={Size.XSMALL} + tooltip={`Sorted by : ${this.doc.treeView_SortCriterion}. click to cycle`} icon={sortings[sorting]?.icon} onPointerDown={e => { downX = e.clientX; @@ -590,7 +591,7 @@ export class TreeView extends React.Component<TreeViewProps> { }} onClick={undoable(e => { if (this.props.isContentActive() && Math.abs(e.clientX - downX) < 3 && Math.abs(e.clientY - downY) < 3) { - !this.props.treeView.outlineMode && (this.doc.treeViewSortCriterion = sortKeys[(curSortIndex + 1) % sortKeys.length]); + !this.props.treeView.outlineMode && (this.doc.treeView_SortCriterion = sortKeys[(curSortIndex + 1) % sortKeys.length]); e.stopPropagation(); } }, 'sort order')} @@ -600,8 +601,8 @@ export class TreeView extends React.Component<TreeViewProps> { <ul style={{ cursor: 'inherit' }} key={expandKey + 'more'} - title="click to change sort order" - className={''} //this.doc.treeViewHideTitle ? 'no-indent' : ''} + title={`Sorted by : ${this.doc.treeView_SortCriterion}. click to cycle`} + className='' //this.doc.treeView_HideTitle ? 'no-indent' : ''} onPointerDown={e => { downX = e.clientX; downY = e.clientY; @@ -609,7 +610,7 @@ export class TreeView extends React.Component<TreeViewProps> { }} onClick={undoable(e => { if (this.props.isContentActive() && Math.abs(e.clientX - downX) < 3 && Math.abs(e.clientY - downY) < 3) { - !this.props.treeView.outlineMode && (this.doc.treeViewSortCriterion = sortKeys[(curSortIndex + 1) % sortKeys.length]); + !this.props.treeView.outlineMode && (this.doc.treeView_SortCriterion = sortKeys[(curSortIndex + 1) % sortKeys.length]); e.stopPropagation(); } }, 'sort order')}> @@ -683,7 +684,7 @@ export class TreeView extends React.Component<TreeViewProps> { { this: this.doc.isTemplateForField && this.props.dataDoc ? this.props.dataDoc : this.doc, heading: this.props.treeViewParent.title, - checked: this.doc.treeViewChecked === 'check' ? 'x' : this.doc.treeViewChecked === 'x' ? 'remove' : 'check', + checked: this.doc.treeView_Checked === 'check' ? 'x' : this.doc.treeView_Checked === 'x' ? 'remove' : 'check', containingTreeView: this.props.treeView.props.Document, }, console.log @@ -698,7 +699,7 @@ export class TreeView extends React.Component<TreeViewProps> { TraceMobx(); const iconType = this.props.treeView.props.styleProvider?.(this.doc, this.props.treeView.props, StyleProp.TreeViewIcon + (this.treeViewOpen ? ':open' : !this.childDocs.length ? ':empty' : '')) || 'question'; const color = StrCast(Doc.UserDoc().userColor); - const checked = this.onCheckedClick ? this.doc.treeViewChecked ?? 'unchecked' : undefined; + const checked = this.onCheckedClick ? this.doc.treeView_Checked ?? 'unchecked' : undefined; return ( <div className={`bullet${this.props.treeView.outlineMode ? '-outline' : ''}`} @@ -748,9 +749,9 @@ export class TreeView extends React.Component<TreeViewProps> { } @action expandNextviewType = () => { - if (this.treeViewOpen && !this.doc.isFolder && !this.props.treeView.outlineMode && !this.doc.treeViewExpandedViewLock) { + if (this.treeViewOpen && !this.doc.isFolder && !this.props.treeView.outlineMode && !this.doc.treeView_ExpandedViewLock) { const next = (modes: any[]) => modes[(modes.indexOf(StrCast(this.treeViewExpandedView)) + 1) % modes.length]; - this.doc.treeViewExpandedView = next(this.validExpandViewTypes); + this.doc.treeView_ExpandedView = next(this.validExpandViewTypes); } this.treeViewOpen = true; }; @@ -759,7 +760,7 @@ export class TreeView extends React.Component<TreeViewProps> { @computed get titleButtons() { const customHeaderButtons = this.props.styleProvider?.(this.doc, this.props.treeView.props, StyleProp.Decorations); const color = StrCast(Doc.UserDoc().userColor); - return this.props.treeViewHideHeaderFields() || this.doc.treeViewHideHeaderFields ? null : ( + return this.props.treeViewHideHeaderFields() || this.doc.treeView_HideHeaderFields ? null : ( <> {customHeaderButtons} {/* e.g.,. hide button is set by dashboardStyleProvider */} <IconButton @@ -771,7 +772,7 @@ export class TreeView extends React.Component<TreeViewProps> { e.stopPropagation(); }} /> - {Doc.noviceMode ? null : this.doc.treeViewExpandedViewLock || Doc.IsSystem(this.doc) ? null : ( + {Doc.noviceMode ? null : this.doc.treeView_ExpandedViewLock || Doc.IsSystem(this.doc) ? null : ( <span className="collectionTreeView-keyHeader" title="type of expanded data" key={this.treeViewExpandedView} onPointerDown={this.expandNextviewType}> {this.treeViewExpandedView} </span> @@ -815,7 +816,7 @@ export class TreeView extends React.Component<TreeViewProps> { onChildClick = () => this.props.onChildClick?.() ?? (this._editTitleScript?.() || ScriptField.MakeFunction(`DocFocusOrOpen(self)`)!); - onChildDoubleClick = () => ScriptCast(this.props.treeView.Document.treeViewChildDoubleClick, !this.props.treeView.outlineMode ? this._openScript?.() : null); + onChildDoubleClick = () => ScriptCast(this.props.treeView.Document.treeView_ChildDoubleClick, !this.props.treeView.outlineMode ? this._openScript?.() : null); refocus = () => this.props.treeView.props.focus(this.props.treeView.props.Document, {}); ignoreEvent = (e: any) => { @@ -861,7 +862,7 @@ export class TreeView extends React.Component<TreeViewProps> { return this.props?.treeView?.props.styleProvider?.(doc, props, property); // properties are inherited from the CollectionTreeView, not the hierarchical parent in the treeView }; onKeyDown = (e: React.KeyboardEvent, fieldProps: FieldViewProps) => { - if (this.doc.treeViewHideHeader || (this.doc.treeViewHideHeaderIfTemplate && this.props.treeView.props.childLayoutTemplate?.()) || this.props.treeView.outlineMode) { + if (this.doc.treeView_HideHeader || (this.doc.treeView_HideHeaderIfTemplate && this.props.treeView.props.childLayoutTemplate?.()) || this.props.treeView.outlineMode) { switch (e.key) { case 'Tab': e.stopPropagation?.(); @@ -1068,7 +1069,7 @@ export class TreeView extends React.Component<TreeViewProps> { // renders the text version of a document as the header. This is used in the file system mode and in other vanilla tree views. @computed get renderTitleAsHeader() { - return this.props.treeView.Document.treeViewHideUnrendered && this.doc.layout_unrendered && !this.doc.treeViewFieldKey ? ( + return this.props.treeView.Document.treeView_HideUnrendered && this.doc.layout_unrendered && !this.doc.treeView_FieldKey ? ( <div></div> ) : ( <> @@ -1089,7 +1090,7 @@ export class TreeView extends React.Component<TreeViewProps> { }; @computed get renderBorder() { - const sorting = StrCast(this.doc.treeViewSortCriterion, TreeSort.None); + const sorting = StrCast(this.doc.treeView_SortCriterion, TreeSort.WhenAdded); const sortings = (this.props.styleProvider?.(this.doc, this.props.treeView.props, StyleProp.TreeViewSortings) ?? {}) as { [key: string]: { color: string; label: string } }; return ( <div className={`treeView-border${this.props.treeView.outlineMode ? TreeViewType.outline : ''}`} style={{ borderColor: sortings[sorting]?.color }}> @@ -1109,7 +1110,7 @@ export class TreeView extends React.Component<TreeViewProps> { render() { TraceMobx(); - const hideTitle = this.doc.treeViewHideHeader || (this.doc.treeViewHideHeaderIfTemplate && this.props.treeView.props.childLayoutTemplate?.()) || this.props.treeView.outlineMode; + const hideTitle = this.doc.treeView_HideHeader || (this.doc.treeView_HideHeaderIfTemplate && this.props.treeView.props.childLayoutTemplate?.()) || this.props.treeView.outlineMode; return this.props.renderedIds?.indexOf(this.doc[Id]) !== -1 ? ( '<' + this.doc.title + '>' // just print the title of documents we've previously rendered in this hierarchical path to avoid cycles ) : ( @@ -1121,9 +1122,9 @@ export class TreeView extends React.Component<TreeViewProps> { // onKeyDown={this.onKeyDown} > <li className="collection-child"> - {hideTitle && this.doc.type !== DocumentType.RTF && !this.doc.treeViewRenderAsBulletHeader // should test for prop 'treeViewRenderDocWithBulletAsHeader" + {hideTitle && this.doc.type !== DocumentType.RTF && !this.doc.treeView_RenderAsBulletHeader // should test for prop 'treeView_RenderDocWithBulletAsHeader" ? this.renderEmbeddedDocument(false, returnFalse) - : this.renderBulletHeader(hideTitle ? this.renderDocumentAsHeader(!this.doc.treeViewRenderAsBulletHeader) : this.renderTitleAsHeader, this._editTitle)} + : this.renderBulletHeader(hideTitle ? this.renderDocumentAsHeader(!this.doc.treeView_RenderAsBulletHeader) : this.renderTitleAsHeader, this._editTitle)} </li> </div> ); @@ -1131,7 +1132,7 @@ export class TreeView extends React.Component<TreeViewProps> { public static sortDocs(childDocs: Doc[], criterion: string | undefined) { const docs = childDocs.slice(); - if (criterion !== TreeSort.None) { + if (criterion !== TreeSort.WhenAdded) { const sortAlphaNum = (a: string, b: string): 0 | 1 | -1 => { const reN = /[0-9]*$/; const aA = a.replace(reN, '') ? a.replace(reN, '') : +a; // get rid of trailing numbers @@ -1146,8 +1147,8 @@ export class TreeView extends React.Component<TreeViewProps> { } }; docs.sort(function (d1, d2): 0 | 1 | -1 { - const a = criterion === TreeSort.Up ? d2 : d1; - const b = criterion === TreeSort.Up ? d1 : d2; + const a = criterion === TreeSort.AlphaUp ? d2 : d1; + const b = criterion === TreeSort.AlphaUp ? d1 : d2; const first = a[criterion === TreeSort.Zindex ? 'zIndex' : 'title']; const second = b[criterion === TreeSort.Zindex ? 'zIndex' : 'title']; if (typeof first === 'number' && typeof second === 'number') return first - second > 0 ? 1 : -1; @@ -1162,7 +1163,7 @@ export class TreeView extends React.Component<TreeViewProps> { childDocs: Doc[], treeView: CollectionTreeView, parentTreeView: CollectionTreeView | TreeView | undefined, - treeViewParent: Doc, + treeView_Parent: Doc, dataDoc: Doc | undefined, parentCollectionDoc: Doc | undefined, containerPrevSibling: Doc | undefined, @@ -1176,7 +1177,7 @@ export class TreeView extends React.Component<TreeViewProps> { isContentActive: (outsideReaction?: boolean) => boolean, panelWidth: () => number, renderDepth: number, - treeViewHideHeaderFields: () => boolean, + treeView_HideHeaderFields: () => boolean, renderedIds: string[], onCheckedClick: undefined | (() => ScriptField), onChildClick: undefined | (() => ScriptField), @@ -1193,19 +1194,19 @@ export class TreeView extends React.Component<TreeViewProps> { hierarchyIndex?: number[], renderCount?: number ) { - const viewSpecScript = Cast(treeViewParent.viewSpecScript, ScriptField); + const viewSpecScript = Cast(treeView_Parent.viewSpecScript, ScriptField); if (viewSpecScript) { childDocs = childDocs.filter(d => viewSpecScript.script.run({ doc: d }, console.log).result); } - const docs = TreeView.sortDocs(childDocs, StrCast(treeViewParent.treeViewSortCriterion, TreeSort.None)); + const docs = TreeView.sortDocs(childDocs, StrCast(treeView_Parent.treeView_SortCriterion, TreeSort.WhenAdded)); const rowWidth = () => panelWidth() - treeBulletWidth() * (treeView.props.NativeDimScaling?.() || 1); - const treeViewRefs = new Map<Doc, TreeView | undefined>(); + const treeView_Refs = new Map<Doc, TreeView | undefined>(); return docs .filter(child => child instanceof Doc) .map((child, i) => { if (renderCount && i > renderCount) return null; - const pair = Doc.GetLayoutDataDocPair(treeViewParent, dataDoc, child); + const pair = Doc.GetLayoutDataDocPair(treeView_Parent, dataDoc, child); if (!pair.layout || pair.data instanceof Promise) { return null; } @@ -1218,11 +1219,11 @@ export class TreeView extends React.Component<TreeViewProps> { FormattedTextBox.SelectOnLoad = child[Id]; TreeView._editTitleOnLoad = editTitle ? { id: child[Id], parent } : undefined; Doc.AddDocToList(newParent, fieldKey, child, addAfter, false); - newParent.treeViewOpen = true; + newParent.treeView_Open = true; Doc.SetContainer(child, treeView.Document); } }; - const indent = i === 0 ? undefined : (editTitle: boolean) => dentDoc(editTitle, docs[i - 1], undefined, treeViewRefs.get(docs[i - 1])); + const indent = i === 0 ? undefined : (editTitle: boolean) => dentDoc(editTitle, docs[i - 1], undefined, treeView_Refs.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); @@ -1233,10 +1234,10 @@ export class TreeView extends React.Component<TreeViewProps> { return ( <TreeView key={child[Id]} - ref={r => treeViewRefs.set(child, r ? r : undefined)} + ref={r => treeView_Refs.set(child, r ? r : undefined)} document={pair.layout} dataDoc={pair.data} - treeViewParent={treeViewParent} + treeViewParent={treeView_Parent} prevSibling={docs[i]} // TODO: [AL] add these hierarchyIndex={hierarchyIndex ? [...hierarchyIndex, i + 1] : undefined} @@ -1248,7 +1249,7 @@ export class TreeView extends React.Component<TreeViewProps> { onCheckedClick={onCheckedClick} onChildClick={onChildClick} renderDepth={renderDepth} - removeDoc={StrCast(treeViewParent.treeViewFreezeChildren).includes('remove') ? undefined : remove} + removeDoc={StrCast(treeView_Parent.treeView_FreezeChildren).includes('remove') ? undefined : remove} addDocument={addDocument} styleProvider={styleProvider} panelWidth={rowWidth} @@ -1259,7 +1260,7 @@ export class TreeView extends React.Component<TreeViewProps> { addDocTab={addDocTab} ScreenToLocalTransform={screenToLocalXf} isContentActive={isContentActive} - treeViewHideHeaderFields={treeViewHideHeaderFields} + treeViewHideHeaderFields={treeView_HideHeaderFields} renderedIds={renderedIds} skipFields={skipFields} firstLevel={firstLevel} diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx index fb8ec93b2..89deb733a 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx @@ -21,6 +21,8 @@ export interface CollectionFreeFormLinkViewProps { LinkDocs: Doc[]; } +// props.screentolocatransform + @observer export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFormLinkViewProps> { @observable _opacity: number = 0; @@ -59,7 +61,7 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo 0 ); // since the render code depends on querying the Dom through getBoudndingClientRect, we need to delay triggering render() setTimeout( - action(() => (!LinkDocs.length || !linkDoc.link_displayLine) && (this._opacity = 0.05)), + action(() => (!LinkDocs.length || !(linkDoc.link_displayLine || Doc.UserDoc().showLinkLines)) && (this._opacity = 0.05)), 750 ); // this will unhighlight the link line. const a = A.ContentDiv.getBoundingClientRect(); @@ -235,11 +237,12 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo bActive, textX, textY, - // pt1, - // pt2, + // fully connected + pt1, + pt2, // this code adds space between links - pt1: [pt1[0] + pt1normalized[0] * 13, pt1[1] + pt1normalized[1] * 13], - pt2: [pt2[0] + pt2normalized[0] * 13, pt2[1] + pt2normalized[1] * 13], + // pt1: [pt1[0] + pt1normalized[0] * 13, pt1[1] + pt1normalized[1] * 13], + // pt2: [pt2[0] + pt2normalized[0] * 13, pt2[1] + pt2normalized[1] * 13], }; } @@ -269,7 +272,7 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo link.link_displayArrow = false; } - return link.opacity === 0 || !a.width || !b.width || (!link.link_displayLine && !aActive && !bActive) ? null : ( + return link.opacity === 0 || !a.width || !b.width || (!(Doc.UserDoc().showLinkLines || link.link_displayLine) && !aActive && !bActive) ? null : ( <> <defs> <marker id={`${link[Id] + 'arrowhead'}`} markerWidth="4" markerHeight="3" refX="0" refY="1.5" orient="auto"> diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss index c6419885b..e4ae251c8 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss @@ -153,7 +153,12 @@ overflow-y: auto; overflow-x: hidden; } - +.collectionFreeFormView-brushView { + pointer-events: none; + position: absolute; + transition: opacity 0.5s; + z-index: 1000; +} .collectionfreeformview-container { // touch action none means that the browser will handle none of the touch actions. this allows us to implement our own actions. touch-action: none; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index e1455525e..f5cc1eb53 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -237,7 +237,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection onChildClickHandler = () => this.props.childClickScript || ScriptCast(this.Document.onChildClick); onChildDoubleClickHandler = () => this.props.childDoubleClickScript || ScriptCast(this.Document.onChildDoubleClick); elementFunc = () => this._layoutElements; - shrinkWrap = () => { + fitContentOnce = () => { if (this.props.DocumentView?.().nativeWidth) return; const vals = this.fitToContentVals; this.layoutDoc._freeform_panX = vals.bounds.cx; @@ -319,7 +319,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection // focus on the document in the collection const didMove = !cantTransform && !anchor.z && (panX !== savedState.panX || panY !== savedState.panY || scale !== savedState.scale); if (didMove) options.didMove = true; - // glr: freeform transform speed can be set by adjusting presTransition field - needs a way of knowing when presentation is not active... + // glr: freeform transform speed can be set by adjusting presentation_transition field - needs a way of knowing when presentation is not active... if (didMove) { const focusTime = options?.instant ? 0 : options.zoomTime ?? 500; (options.zoomScale ?? options.willZoomCentered) && scale && (this.Document[this.scaleFieldKey] = scale); @@ -681,6 +681,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection case GestureUtils.Gestures.Stroke: const points = ge.points; const B = this.getTransform().transformBounds(ge.bounds.left, ge.bounds.top, ge.bounds.width, ge.bounds.height); + console.log(ge.bounds.left, ge.bounds.top, ge.bounds.width, ge.bounds.height); const inkDoc = Docs.Create.InkDocument( ActiveInkColor(), ActiveInkWidth() * this.props.ScreenToLocalTransform().Scale, @@ -1050,7 +1051,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection onPointerWheel = (e: React.WheelEvent): void => { if (this.Document._isGroup || !this.isContentActive()) return; // group style collections neither pan nor zoom PresBox.Instance?.pauseAutoPres(); - if (this.layoutDoc._Transform || this.props.Document.treeViewOutlineMode === TreeViewType.outline) return; + if (this.layoutDoc._Transform || this.props.Document.treeView_OutlineMode === TreeViewType.outline) return; e.stopPropagation(); const docHeight = NumCast(this.rootDoc[Doc.LayoutFieldKey(this.rootDoc) + '_nativeHeight'], this.nativeHeight); const scrollable = NumCast(this.layoutDoc[this.scaleFieldKey], 1) === 1 && docHeight > this.props.PanelHeight() / this.nativeDimScaling + 1e-4; @@ -1318,7 +1319,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection layout_showTitle={this.props.childlayout_showTitle} dontRegisterView={this.props.dontRenderDocuments || this.props.dontRegisterView} pointerEvents={this.pointerEvents} - //fitContentsToBox={this.props.fitContentsToBox || BoolCast(this.props.treeViewFreezeChildDimensions)} // bcz: check this + //fitContentsToBox={this.props.fitContentsToBox || BoolCast(this.props.treeView_FreezeChildDimensions)} // bcz: check this /> ); } @@ -1537,7 +1538,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection getAnchor = (addAsAnnotation: boolean, pinProps?: PinProps) => { // create an anchor that saves information about the current state of the freeform view (pan, zoom, view type) - const anchor = Docs.Create.ConfigDocument({ title: 'ViewSpec - ' + StrCast(this.layoutDoc._type_collection), layout_unrendered: true, presTransition: 500, annotationOn: this.rootDoc }); + const anchor = Docs.Create.ConfigDocument({ title: 'ViewSpec - ' + StrCast(this.layoutDoc._type_collection), layout_unrendered: true, presentation_transition: 500, annotationOn: this.rootDoc }); PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), pannable: !this.Document._isGroup, type_collection: true, filters: true } }, this.rootDoc); if (addAsAnnotation) { @@ -1594,6 +1595,15 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection elements => (this._layoutElements = elements || []), { fireImmediately: true, name: 'doLayout' } ); + + this._disposers.fitContent = reaction( + () => this.rootDoc.fitContentOnce, + fitContentOnce => { + if (fitContentOnce) this.fitContentOnce(); + this.rootDoc.fitContentOnce = undefined; + }, + { fireImmediately: true, name: 'fitContent' } + ); }) ); } @@ -1784,6 +1794,14 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection !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: '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' }); } @@ -1866,6 +1884,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection showPresPaths = () => (CollectionFreeFormView.ShowPresPaths ? PresBox.Instance.getPaths(this.rootDoc) : null); + brushedView = () => this._brushedView; @computed get marqueeView() { TraceMobx(); return ( @@ -1908,13 +1927,13 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection </div> ) : null} <CollectionFreeFormViewPannableContents - brushView={this._brushedView} + brushedView={this.brushedView} isAnnotationOverlay={this.isAnnotationOverlay} isAnnotationOverlayScrollable={this.props.isAnnotationOverlayScrollable} transform={this.contentTransform} zoomScaling={this.zoomScaling} presPaths={this.showPresPaths} - presPinView={BoolCast(this.Document.presPinView)} + presPinView={BoolCast(this.Document.config_pinView)} transition={this._panZoomTransition ? `transform ${this._panZoomTransition}ms` : Cast(this.layoutDoc._viewTransition, 'string', Cast(this.props.DocumentView?.()?.rootDoc._viewTransition, 'string', null))} viewDefDivClick={this.props.viewDefDivClick}> {this.children} @@ -1945,19 +1964,19 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection }; @action - brushView = (viewport: { width: number; height: number; panX: number; panY: number }) => { - this._brushedView = { ...viewport, panX: viewport.panX - viewport.width / 2, panY: viewport.panY - viewport.height / 2, opacity: 1 }; + brushView = (viewport: { width: number; height: number; panX: number; panY: number }, transTime: number) => { this._brushtimer1 && clearTimeout(this._brushtimer1); this._brushtimer && clearTimeout(this._brushtimer); + this._brushedView = { width: 0, height: 0, panX: 0, panY: 0, opacity: 0 }; this._brushtimer1 = setTimeout( action(() => { - this._brushedView.opacity = 0; + this._brushedView = { ...viewport, panX: viewport.panX - viewport.width / 2, panY: viewport.panY - viewport.height / 2, opacity: 1 }; this._brushtimer = setTimeout( - action(() => (this._brushedView = { width: 0, height: 0, panX: 0, panY: 0, opacity: 0 })), - 500 + action(() => (this._brushedView.opacity = 0)), + 2500 ); }), - 1000 + transTime + 1 ); }; lightboxPanelWidth = () => Math.max(0, this.props.PanelWidth() - 30); @@ -2084,7 +2103,7 @@ interface CollectionFreeFormViewPannableContentsProps { presPinView?: boolean; isAnnotationOverlay: boolean | undefined; isAnnotationOverlayScrollable: boolean | undefined; - brushView: { panX: number; panY: number; width: number; height: number; opacity: number }; + brushedView: () => { panX: number; panY: number; width: number; height: number; opacity: number }; } @observer @@ -2156,6 +2175,7 @@ class CollectionFreeFormViewPannableContents extends React.Component<CollectionF } render() { + const brushedView = this.props.brushedView(); return ( <div className={'collectionfreeformview' + (this.props.viewDefDivClick ? '-viewDef' : '-none')} @@ -2173,21 +2193,18 @@ class CollectionFreeFormViewPannableContents extends React.Component<CollectionF //willChange: "transform" }}> {this.props.children} - {!this.props.brushView.width ? null : ( + { <div className="collectionFreeFormView-brushView" style={{ - zIndex: 1000, - opacity: this.props.brushView.opacity, - border: 'orange solid 2px', - position: 'absolute', - transform: `translate(${this.props.brushView.panX}px, ${this.props.brushView.panY}px)`, - width: this.props.brushView.width, - height: this.props.brushView.height, - transition: 'opacity 2s', + opacity: brushedView.opacity, + transform: `translate(${brushedView.panX}px, ${brushedView.panY}px)`, + width: brushedView.width, + height: brushedView.height, + border: `orange solid ${brushedView.width * 0.005}px`, }} /> - )} + } {this.presPaths} </div> ); diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 7c53bfdbe..1c3da1dc5 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -170,7 +170,15 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque TreeView._editTitleOnLoad = { id: slide[Id], parent: undefined }; this.props.addDocument?.(slide); e.stopPropagation(); - }*/ else if (!e.ctrlKey && !e.metaKey && SelectionManager.Views().length < 2) { + }*/ else if (e.key === 'p' && e.ctrlKey) { + e.preventDefault(); + (async () => { + const text: string = await navigator.clipboard.readText(); + const ns = text.split('\n').filter(t => t.trim() !== '\r' && t.trim() !== ''); + this.pasteTable(ns, x, y); + })(); + e.stopPropagation(); + } 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)); @@ -185,44 +193,26 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque // any row that has only one column is a section header-- this header is then added as a column to subsequent rows until the next header // assumes each cell is a string or a number pasteTable(ns: string[], x: number, y: number) { - while (ns.length > 0 && ns[0].split('\t').length < 2) { - ns.splice(0, 1); - } - if (ns.length > 0) { - const columns = ns[0].split('\t'); - const docList: Doc[] = []; - let groupAttr: string | number = ''; - const rowProto = new Doc(); - rowProto.title = rowProto.Id; - rowProto._width = 200; - rowProto.isDataDoc = true; - for (let i = 1; i < ns.length - 1; i++) { - const values = ns[i].split('\t'); - if (values.length === 1 && columns.length > 1) { - groupAttr = values[0]; - continue; - } - const docDataProto = Doc.MakeDelegate(rowProto); - docDataProto.isDataDoc = true; - columns.forEach((col, i) => (docDataProto[columns[i]] = values.length > i ? (values[i].indexOf(Number(values[i]).toString()) !== -1 ? Number(values[i]) : values[i]) : undefined)); - if (groupAttr) { - docDataProto._group = groupAttr; - } - docDataProto.title = i.toString(); - const doc = Doc.MakeDelegate(docDataProto); - doc._width = 200; - docList.push(doc); + let csvRows = []; + const headers = ns[0].split('\t'); + csvRows.push(headers.join(',')); + ns[0] = ''; + const eachCell = ns.join('\t').split('\t') + let eachRow = [] + for (let i=1; i<eachCell.length; i++){ + eachRow.push(eachCell[i].replace(/\,/g, '')); + if (i % headers.length == 0){ + csvRows.push(eachRow) + eachRow = []; } - const newCol = Docs.Create.SchemaDocument([...(groupAttr ? [new SchemaHeaderField('_group', '#f1efeb')] : []), ...columns.filter(c => c).map(c => new SchemaHeaderField(c, '#f1efeb'))], docList, { - x: x, - y: y, - title: 'droppedTable', - _width: 300, - _height: 100, - }); - - this.props.addDocument?.(newCol); } + + const blob = new Blob([csvRows.join('\n')], {type: 'text/csv'}) + const options = { x: x, y: y, title: 'droppedTable', _width: 300, _height: 100, type:'text/csv'} + const file = new File([blob], 'droppedTable', options); + const loading = Docs.Create.LoadingDocument(file, options); + DocUtils.uploadFileToDoc(file, {}, loading); + this.props.addDocument?.(loading); } @action diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.scss b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.scss index f87a06033..cb0d5e03f 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.scss +++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.scss @@ -9,6 +9,12 @@ flex-direction: column; width: 100%; align-items: center; + position: relative; + > .iconButton-container { + top: 0; + left: 0; + position: absolute; + } .contentFittingDocumentView { width: unset; diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx index 10532b9d9..80da4e1a2 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx @@ -1,3 +1,5 @@ +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { Button } from 'browndash-components'; import { action, computed } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; @@ -6,7 +8,7 @@ import { BoolCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types import { returnFalse } from '../../../../Utils'; import { DragManager, dropActionType } from '../../../util/DragManager'; import { Transform } from '../../../util/Transform'; -import { undoBatch } from '../../../util/UndoManager'; +import { undoable, undoBatch } from '../../../util/UndoManager'; import { DocumentView } from '../../nodes/DocumentView'; import { CollectionSubView } from '../CollectionSubView'; import './CollectionMulticolumnView.scss'; @@ -301,6 +303,9 @@ export class CollectionMulticolumnView extends CollectionSubView() { collector.push( <div className="document-wrapper" key={'wrapper' + i} style={{ width: width() }}> {this.getDisplayDoc(layout, dxf, docwidth, docheight, shouldNotScale)} + <Button icon={<FontAwesomeIcon icon={'times'} size={'lg'} />} onClick={undoable(e => { + this.props.removeDocument?.(layout); + }, "close doc")} color={StrCast(Doc.UserDoc().userColor)} /> <WidthLabel layout={layout} collectionDoc={Document} /> </div>, <ResizeBar |
