diff options
| author | mehekj <mehek.jethani@gmail.com> | 2021-09-20 22:25:19 -0400 |
|---|---|---|
| committer | mehekj <mehek.jethani@gmail.com> | 2021-09-20 22:25:19 -0400 |
| commit | a8d8c9a115d1de3946a4f3d971c953f4b1222551 (patch) | |
| tree | 86f56b6406216e694b9baa93af28f5ed5763c311 /src/client/views/collections | |
| parent | 64e265d9cba009469081fdf4ba3272c78a3a76a8 (diff) | |
| parent | e295f6694bed9a3a35a0858c8f17745ef1506f51 (diff) | |
Merge branch 'master' into temporalmedia-mehek
Diffstat (limited to 'src/client/views/collections')
11 files changed, 154 insertions, 122 deletions
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx index aefa1ec3d..2c2d5dc75 100644 --- a/src/client/views/collections/CollectionMenu.tsx +++ b/src/client/views/collections/CollectionMenu.tsx @@ -42,8 +42,13 @@ import { CollectionViewType, COLLECTION_BORDER_WIDTH } from "./CollectionView"; import { TabDocView } from "./TabDocView"; import { Colors } from "../global/globalEnums"; +interface CollectionMenuProps { + panelHeight: () => number; + panelWidth: () => number; +} + @observer -export class CollectionMenu extends AntimodeMenu<AntimodeMenuProps> { +export class CollectionMenu extends AntimodeMenu<CollectionMenuProps>{ @observable static Instance: CollectionMenu; @observable SelectedCollection: DocumentView | undefined; @@ -93,13 +98,9 @@ export class CollectionMenu extends AntimodeMenu<AntimodeMenuProps> { return new Transform(-translateX, -translateY, 1 / scale); } - panelWidth100 = () => 100; - panelHeight35 = () => 35; - @computed get contMenuButtons() { - trace(); const selDoc = Doc.UserDoc().contextMenuBtns; - return !(selDoc instanceof Doc) ? (null) : <div className="collectionMenu-contMenuButtons" ref={this._docBtnRef} style={{ height: "35px" }} > + return !(selDoc instanceof Doc) ? (null) : <div className="collectionMenu-contMenuButtons" ref={this._docBtnRef} style={{ height: this.props.panelHeight() }} > <CollectionLinearView Document={selDoc} DataDoc={undefined} @@ -122,8 +123,8 @@ export class CollectionMenu extends AntimodeMenu<AntimodeMenuProps> { pinToPres={emptyFunction} removeDocument={returnFalse} ScreenToLocalTransform={this.buttonBarXf} - PanelWidth={this.panelWidth100} - PanelHeight={this.panelHeight35} + PanelWidth={this.props.panelWidth} + PanelHeight={this.props.panelHeight} renderDepth={0} focus={emptyFunction} whenChildContentsActiveChanged={emptyFunction} @@ -176,7 +177,7 @@ export class CollectionMenu extends AntimodeMenu<AntimodeMenuProps> { } } -interface CollectionMenuProps { +interface CollectionViewMenuProps { type: CollectionViewType; fieldKey: string; docView: DocumentView; @@ -185,7 +186,7 @@ interface CollectionMenuProps { const stopPropagation = (e: React.SyntheticEvent) => e.stopPropagation(); @observer -export class CollectionViewBaseChrome extends React.Component<CollectionMenuProps> { +export class CollectionViewBaseChrome extends React.Component<CollectionViewMenuProps> { //(!)?\(\(\(doc.(\w+) && \(doc.\w+ as \w+\).includes\(\"(\w+)\"\) get document() { return this.props.docView?.props.Document; } @@ -628,14 +629,14 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp } @observer -export class CollectionDockingChrome extends React.Component<CollectionMenuProps> { +export class CollectionDockingChrome extends React.Component<CollectionViewMenuProps> { render() { return (null); } } @observer -export class CollectionFreeFormViewChrome extends React.Component<CollectionMenuProps & { isOverlay: boolean, isDoc?: boolean }> { +export class CollectionFreeFormViewChrome extends React.Component<CollectionViewMenuProps & { isOverlay: boolean, isDoc?: boolean }> { public static Instance: CollectionFreeFormViewChrome; constructor(props: any) { super(props); @@ -677,12 +678,12 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu private _palette = ["#D0021B", "#F5A623", "#F8E71C", "#8B572A", "#7ED321", "#417505", "#9013FE", "#4A90E2", "#50E3C2", "#B8E986", "#000000", "#4A4A4A", "#9B9B9B", "#FFFFFF", ""]; private _width = ["1", "5", "10", "100"]; private _dotsize = [10, 20, 30, 40]; - private _draw = ["∿", "⎯", "→", "↔︎", "ロ", "O"]; - private _head = ["", "", "", "arrow", "", ""]; - private _end = ["", "", "arrow", "arrow", "", ""]; - private _shapePrims = ["", "line", "line", "line", "rectangle", "circle"]; - private _title = ["pen", "line", "line with arrow", "line with double arrows", "square", "circle",]; - private _faName = ["pen-fancy", "minus", "long-arrow-alt-right", "arrows-alt-h", "square", "circle"]; + private _draw = ["∿", "=", "⎯", "→", "↔︎", "ロ", "O"]; + private _head = ["", "", "", "", "arrow", "", ""]; + private _end = ["", "", "", "arrow", "arrow", "", ""]; + private _shapePrims = ["", "", "line", "line", "line", "rectangle", "circle"]; + private _title = ["pen", "highlighter", "line", "line with arrow", "line with double arrows", "square", "circle"]; + private _faName = ["pen-fancy", "highlighter", "minus", "long-arrow-alt-right", "arrows-alt-h", "square", "circle"]; @observable _selectedPrimitive = this._shapePrims.length; @observable _keepPrimitiveMode = false; // for whether primitive selection enters a one-shot or persistent mode @observable _colorBtn = false; @@ -692,6 +693,7 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu @action clearKeepPrimitiveMode() { this._selectedPrimitive = this._shapePrims.length; } @action primCreated() { if (!this._keepPrimitiveMode) { //get out of ink mode after each stroke= + if (CurrentUserUtils.SelectedTool === InkTool.Highlighter && GestureOverlay.Instance.SavedColor) SetActiveInkColor(GestureOverlay.Instance.SavedColor); CurrentUserUtils.SelectedTool = InkTool.None; this._selectedPrimitive = this._shapePrims.length; SetActiveArrowStart("none"); @@ -732,7 +734,13 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu this._keepPrimitiveMode = keep; if (this._selectedPrimitive !== i) { this._selectedPrimitive = i; - CurrentUserUtils.SelectedTool = InkTool.Pen; + if (this._title[i] === "highlighter") { + CurrentUserUtils.SelectedTool = InkTool.Highlighter; + GestureOverlay.Instance.SavedColor = ActiveInkColor(); + SetActiveInkColor("rgba(245, 230, 95, 0.75)"); + } else { + CurrentUserUtils.SelectedTool = InkTool.Pen; + } SetActiveArrowStart(this._head[i]); SetActiveArrowEnd(this._end[i]); SetActiveBezierApprox("300"); @@ -859,7 +867,7 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu } } @observer -export class CollectionStackingViewChrome extends React.Component<CollectionMenuProps> { +export class CollectionStackingViewChrome extends React.Component<CollectionViewMenuProps> { @observable private _currentKey: string = ""; @observable private suggestions: string[] = []; @@ -980,7 +988,7 @@ export class CollectionStackingViewChrome extends React.Component<CollectionMenu @observer -export class CollectionSchemaViewChrome extends React.Component<CollectionMenuProps> { +export class CollectionSchemaViewChrome extends React.Component<CollectionViewMenuProps> { // private _textwrapAllRows: boolean = Cast(this.document.textwrappedSchemaRows, listSpec("string"), []).length > 0; get document() { return this.props.docView.props.Document; } @@ -1028,7 +1036,7 @@ export class CollectionSchemaViewChrome extends React.Component<CollectionMenuPr } @observer -export class CollectionTreeViewChrome extends React.Component<CollectionMenuProps> { +export class CollectionTreeViewChrome extends React.Component<CollectionViewMenuProps> { get document() { return this.props.docView.props.Document; } get sortAscending() { @@ -1065,7 +1073,7 @@ export class CollectionTreeViewChrome extends React.Component<CollectionMenuProp // Enter scroll speed for 3D Carousel @observer -export class Collection3DCarouselViewChrome extends React.Component<CollectionMenuProps> { +export class Collection3DCarouselViewChrome extends React.Component<CollectionViewMenuProps> { get document() { return this.props.docView.props.Document; } @computed get scrollSpeed() { return this.document._autoScrollSpeed; @@ -1106,7 +1114,7 @@ export class Collection3DCarouselViewChrome extends React.Component<CollectionMe * Chrome for grid view. */ @observer -export class CollectionGridViewChrome extends React.Component<CollectionMenuProps> { +export class CollectionGridViewChrome extends React.Component<CollectionViewMenuProps> { private clicked: boolean = false; private entered: boolean = false; diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx index 0ef6f852a..9577256c9 100644 --- a/src/client/views/collections/CollectionStackedTimeline.tsx +++ b/src/client/views/collections/CollectionStackedTimeline.tsx @@ -379,10 +379,11 @@ export class CollectionStackedTimeline extends CollectionSubView< startTag: string, endTag: string, anchorStartTime?: number, - anchorEndTime?: number + anchorEndTime?: number, + docAnchor?: Doc ) { if (anchorStartTime === undefined) return rootDoc; - const anchor = Docs.Create.LabelDocument({ + const anchor = docAnchor ?? Docs.Create.LabelDocument({ title: ComputedField.MakeFunction( `"#" + formatToTime(self["${startTag}"]) + "-" + formatToTime(self["${endTag}"])` ) as any, diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 540bfd1ef..648ff5087 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -575,7 +575,6 @@ export class CollectionStackingView extends CollectionSubView<StackingDocument, }; const buttonMenu = this.rootDoc.buttonMenu; const noviceExplainer = this.rootDoc.explainer; - console.log(noviceExplainer); return ( <> {buttonMenu || noviceExplainer ? <div className="documentButtonMenu"> diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 06d20f015..cb8b55cb2 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -216,7 +216,7 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?: const targetDocments = DocListCast(this.dataDoc[this.props.fieldKey]); const someMoved = !docDragData.userDropAction && docDragData.draggedDocuments.some(drag => targetDocments.includes(drag)); if (someMoved) docDragData.droppedDocuments = docDragData.droppedDocuments.map((drop, i) => targetDocments.includes(docDragData.draggedDocuments[i]) ? docDragData.draggedDocuments[i] : drop); - if ((!dropAction || dropAction === "move" || someMoved) && docDragData.moveDocument) { + if ((!dropAction || dropAction === "same" || dropAction === "move" || someMoved) && docDragData.moveDocument) { const movedDocs = docDragData.droppedDocuments.filter((d, i) => docDragData.draggedDocuments[i] === d); const addedDocs = docDragData.droppedDocuments.filter((d, i) => docDragData.draggedDocuments[i] !== d); if (movedDocs.length) { diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 4d62a1af4..3852987b9 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -108,7 +108,7 @@ export class CollectionTreeView extends CollectionSubView<Document, Partial<coll protected onInternalPreDrop = (e: Event, de: DragManager.DropEvent, targetAction: dropActionType) => { const dragData = de.complete.docDragData; if (dragData) { - const isInTree = () => dragData.draggedDocuments.some(d => d.context === this.doc && this.childDocs.includes(d)); + const isInTree = () => Doc.AreProtosEqual(dragData.treeViewDoc, this.props.Document) || dragData.draggedDocuments.some(d => d.context === this.doc && this.childDocs.includes(d)); dragData.dropAction = targetAction && !isInTree() ? targetAction : this.doc === dragData?.treeViewDoc ? "same" : dragData.dropAction; } } @@ -267,16 +267,17 @@ export class CollectionTreeView extends CollectionSubView<Document, Partial<coll return hideTitle ? (null) : (this.outlineMode ? this.documentTitle : this.editableTitle)(this.treeChildren); } + return35 = () => 35; @computed get buttonMenu() { - const menuDoc:Doc = Cast(this.rootDoc.buttonMenuDoc, Doc, null); + const menuDoc: Doc = Cast(this.rootDoc.buttonMenuDoc, Doc, null); // To create a multibutton menu add a CollectionLinearView - if (menuDoc){ - + if (menuDoc) { + const width: number = NumCast(menuDoc._width, 30); const height: number = NumCast(menuDoc._height, 30); console.log(menuDoc.title, width, height); return (<div className="buttonMenu-docBtn" - style = {{width: width, height: height}}> + style={{ width: width, height: height }}> <DocumentView Document={menuDoc} DataDoc={menuDoc} @@ -289,8 +290,8 @@ export class CollectionTreeView extends CollectionSubView<Document, Partial<coll rootSelected={this.props.isSelected} removeDocument={this.props.removeDocument} ScreenToLocalTransform={Transform.Identity} - PanelWidth={() => 35} - PanelHeight={() => 35} + PanelWidth={this.return35} + PanelHeight={this.return35} renderDepth={this.props.renderDepth + 1} focus={emptyFunction} styleProvider={this.props.styleProvider} @@ -302,13 +303,14 @@ export class CollectionTreeView extends CollectionSubView<Document, Partial<coll docRangeFilters={this.props.docRangeFilters} searchFilterDocs={this.props.searchFilterDocs} ContainingCollectionView={undefined} - ContainingCollectionDoc={undefined} + ContainingCollectionDoc={undefined} /> </div>); } } - + @observable _explainerHeight: number = 0; + @computed get nativeWidth() { return Doc.NativeWidth(this.Document, undefined, true); } @computed get nativeHeight() { return Doc.NativeHeight(this.Document, undefined, true); } @@ -336,30 +338,30 @@ export class CollectionTreeView extends CollectionSubView<Document, Partial<coll const noviceExplainer = this.rootDoc.explainer; return !(this.doc instanceof Doc) || !this.treeChildren ? (null) : - <> - {this.titleBar} - <div className="collectionTreeView-container" - style={this.outlineMode ? { transform: `scale(${this.contentScaling})`, width: `calc(${100 / this.contentScaling}%)` } : {}} - onContextMenu={this.onContextMenu}> - {buttonMenu || noviceExplainer ? <div className="documentButtonMenu"> - {buttonMenu ? this.buttonMenu : null} - {Doc.UserDoc().noviceMode && noviceExplainer ? - <div className="documentExplanation"> - {noviceExplainer} - </div> - : null - } - </div> : null} - <div className="collectionTreeView-dropTarget" - style={{ background: background(), paddingLeft: `${this.paddingX()}px`, paddingRight: `${this.paddingX()}px`, paddingBottom: `${this.paddingBot()}px`, paddingTop: `${this.paddingTop()}px`, pointerEvents: pointerEvents() }} - onWheel={e => e.stopPropagation()} - onDrop={this.onTreeDrop} - ref={this.createTreeDropTarget}> - <ul className={`no-indent${this.outlineMode ? "-outline" : ""}`} > - {this.treeViewElements} - </ul> - </div > - </div> - </>; + <> + {this.titleBar} + <div className="collectionTreeView-container" + style={this.outlineMode ? { transform: `scale(${this.contentScaling})`, width: `calc(${100 / this.contentScaling}%)` } : {}} + onContextMenu={this.onContextMenu}> + {buttonMenu || noviceExplainer ? <div className="documentButtonMenu" ref={action((r: HTMLDivElement) => r && (this._explainerHeight = r.getBoundingClientRect().height))}> + {buttonMenu ? this.buttonMenu : null} + {Doc.UserDoc().noviceMode && noviceExplainer ? + <div className="documentExplanation"> + {noviceExplainer} + </div> + : null + } + </div> : null} + <div className="collectionTreeView-dropTarget" + style={{ background: background(), height: `calc(100% - ${this._explainerHeight}px)`, paddingLeft: `${this.paddingX()}px`, paddingRight: `${this.paddingX()}px`, paddingBottom: `${this.paddingBot()}px`, paddingTop: `${this.paddingTop()}px`, pointerEvents: pointerEvents() }} + onWheel={e => e.stopPropagation()} + onDrop={this.onTreeDrop} + ref={this.createTreeDropTarget}> + <ul className={`no-indent${this.outlineMode ? "-outline" : ""}`} > + {this.treeViewElements} + </ul> + </div > + </div> + </>; } }
\ No newline at end of file diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index bc02c44f0..38e027fb3 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -166,7 +166,7 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab !Doc.UserDoc().noviceMode && subItems.push({ description: "Map", event: () => func(CollectionViewType.Map), icon: "globe-americas" }); subItems.push({ description: "Grid", event: () => func(CollectionViewType.Grid), icon: "th-list" }); - if (!Doc.IsSystem(this.rootDoc) && !this.rootDoc.annotationOn) { + if (!Doc.IsSystem(this.rootDoc) && !this.rootDoc.isGroup && !this.rootDoc.annotationOn) { const existingVm = ContextMenu.Instance.findByDescription(category); const catItems = existingVm && "subitems" in existingVm ? existingVm.subitems : []; catItems.push({ description: "Add a Perspective...", addDivider: true, noexpand: true, subitems: subItems, icon: "eye" }); @@ -246,12 +246,6 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab childLayoutTemplate = () => this.props.childLayoutTemplate?.() || Cast(this.rootDoc.childLayoutTemplate, Doc, null); @computed get childLayoutString() { return StrCast(this.rootDoc.childLayoutString); } - /** - * Shows the filter icon if it's a user-created collection which isn't a dashboard and has some docFilters applied on it or on the current dashboard. - */ - @computed get showFilterIcon() { - return this.props.Document.viewType !== CollectionViewType.Docking && !Doc.IsSystem(this.props.Document) && this._subView?.IsFiltered(); - } @observable _subView: any = undefined; @@ -280,12 +274,6 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab style={{ pointerEvents: this.props.layerProvider?.(this.rootDoc) === false ? "none" : undefined }}> {this.showIsTagged()} {this.collectionViewType !== undefined ? this.SubView(this.collectionViewType, props) : (null)} - {this.showFilterIcon ? - <FontAwesomeIcon icon={"filter"} size="lg" - style={{ position: 'absolute', top: '1%', right: '1%', cursor: "pointer", padding: 1, color: this.showFilterIcon === "hasFilter" ? '#18c718bd' : "orange", zIndex: 1 }} - onPointerDown={action(e => { this.props.select(false); CurrentUserUtils.propertiesWidth = 250; e.stopPropagation(); })} - /> - : (null)} </div>); } } diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index aa7b164b0..97de097e0 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -244,6 +244,9 @@ export class TreeView extends React.Component<TreeViewProps> { TreeView._editTitleOnLoad = { id: folder[Id], parent: this.props.parentTreeView }; return this.props.addDocument(folder); } + deleteFolder = () => { + return this.props.removeDoc?.(this.doc); + } preTreeDrop = (e: Event, de: DragManager.DropEvent, targetAction: dropActionType) => { const dragData = de.complete.docDragData; @@ -513,9 +516,11 @@ export class TreeView extends React.Component<TreeViewProps> { } contextMenuItems = () => { const makeFolder = { script: ScriptField.MakeFunction(`scriptContext.makeFolder()`, { scriptContext: "any" })!, icon: "folder-plus", label: "New Folder" }; + const deleteFolder = { script: ScriptField.MakeFunction(`scriptContext.deleteFolder()`, { scriptContext: "any" })!, icon: "folder-plus", label: "Delete Folder" }; + const folderOp = this.childDocs?.length ? makeFolder : deleteFolder; const openAlias = { script: ScriptField.MakeFunction(`openOnRight(getAlias(self))`)!, icon: "copy", label: "Open Alias" }; const focusDoc = { script: ScriptField.MakeFunction(`DocFocusOrOpen(self)`)!, icon: "eye", label: "Focus or Open" }; - return [...this.props.contextMenuItems.filter(mi => !mi.filter ? true : mi.filter.script.run({ doc: this.doc })?.result), ... (this.doc.isFolder ? [makeFolder] : + return [...this.props.contextMenuItems.filter(mi => !mi.filter ? true : mi.filter.script.run({ doc: this.doc })?.result), ... (this.doc.isFolder ? [folderOp] : Doc.IsSystem(this.doc) ? [] : this.props.treeView.fileSysMode && this.doc === Doc.GetProto(this.doc) ? [openAlias, makeFolder] : @@ -853,6 +858,7 @@ export class TreeView extends React.Component<TreeViewProps> { } const dentDoc = (editTitle: boolean, newParent: Doc, addAfter: Doc | undefined, parent: TreeView | CollectionTreeView | undefined) => { + if (parent instanceof TreeView && parent.props.treeView.fileSysMode && !newParent.isFolder) return; const fieldKey = Doc.LayoutFieldKey(newParent); if (remove && fieldKey && Cast(newParent[fieldKey], listSpec(Doc)) !== undefined) { remove(child); @@ -869,7 +875,7 @@ export class TreeView extends React.Component<TreeViewProps> { const childLayout = Doc.Layout(pair.layout); const rowHeight = () => { const aspect = Doc.NativeAspect(childLayout); - return aspect ? Math.min(childLayout[WidthSym](), rowWidth()) / aspect : childLayout[HeightSym](); + return (aspect ? Math.min(childLayout[WidthSym](), rowWidth()) / aspect : childLayout[HeightSym]()); }; return <TreeView key={child[Id]} ref={r => treeViewRefs.set(child, r ? r : undefined)} document={pair.layout} diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx index 3b3e069d8..2cb487588 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx @@ -1,6 +1,6 @@ import { action, computed, IReactionDisposer, observable, reaction } from "mobx"; import { observer } from "mobx-react"; -import { Doc } from "../../../../fields/Doc"; +import { Doc, Field } from "../../../../fields/Doc"; import { Id } from "../../../../fields/FieldSymbols"; import { List } from "../../../../fields/List"; import { NumCast, StrCast } from "../../../../fields/Types"; @@ -180,7 +180,7 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo if (!this.renderData) return (null); const { a, b, pt1norm, pt2norm, aActive, bActive, textX, textY, pt1, pt2 } = this.renderData; LinkManager.currentLink = this.props.LinkDocs[0]; - const linkRelationship = StrCast(LinkManager.currentLink?.linkRelationship); //get string representing relationship + const linkRelationship = Field.toString(LinkManager.currentLink?.linkRelationship as any as Field); //get string representing relationship const linkRelationshipList = Doc.UserDoc().linkRelationshipList as List<string>; const linkColorList = Doc.UserDoc().linkColorList as List<string>; //access stroke color using index of the relationship in the color list (default black) @@ -189,7 +189,7 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo <path className="collectionfreeformlinkview-linkLine" style={{ opacity: this._opacity, strokeDasharray: "2 2", stroke: strokeColor }} d={`M ${pt1[0]} ${pt1[1]} C ${pt1[0] + pt1norm[0]} ${pt1[1] + pt1norm[1]}, ${pt2[0] + pt2norm[0]} ${pt2[1] + pt2norm[1]}, ${pt2[0]} ${pt2[1]}`} /> {textX === undefined ? (null) : <text className="collectionfreeformlinkview-linkText" x={textX} y={textY} onPointerDown={this.pointerDown} > - {StrCast(this.props.LinkDocs[0].description)} + {Field.toString(this.props.LinkDocs[0].description as any as Field)} </text>} </>); } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index c8561d901..94cf1c5a6 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -183,7 +183,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P addDocument = (newBox: Doc | Doc[]) => { let retVal = false; if (newBox instanceof Doc) { - if (retVal = this.props.addDocument?.(newBox) || false) { + if (retVal = (this.props.addDocument?.(newBox) || false)) { this.bringToFront(newBox); this.updateCluster(newBox); } @@ -209,25 +209,6 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P return retVal; } - updateGroupBounds = () => { - if (!this.props.Document._isGroup) return; - const clist = this.childDocs.map(cd => ({ x: NumCast(cd.x), y: NumCast(cd.y), width: cd[WidthSym](), height: cd[HeightSym]() })); - const cbounds = aggregateBounds(clist, 0, 0); - const c = [NumCast(this.layoutDoc.x) + this.layoutDoc[WidthSym]() / 2, NumCast(this.layoutDoc.y) + this.layoutDoc[HeightSym]() / 2]; - const p = [NumCast(this.layoutDoc._panX), NumCast(this.layoutDoc._panY)]; - const pbounds = { - x: (cbounds.x - p[0]) * this.zoomScaling() + c[0], y: (cbounds.y - p[1]) * this.zoomScaling() + c[1], - r: (cbounds.r - p[0]) * this.zoomScaling() + c[0], b: (cbounds.b - p[1]) * this.zoomScaling() + c[1] - }; - - this.layoutDoc._width = (pbounds.r - pbounds.x); - this.layoutDoc._height = (pbounds.b - pbounds.y); - this.layoutDoc._panX = (cbounds.r + cbounds.x) / 2; - this.layoutDoc._panY = (cbounds.b + cbounds.y) / 2; - this.layoutDoc.x = pbounds.x; - this.layoutDoc.y = pbounds.y; - } - isCurrent(doc: Doc) { const dispTime = NumCast(doc._timecodeToShow, -1); const endTime = NumCast(doc._timecodeToHide, dispTime + 1.5); @@ -269,8 +250,6 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P !StrListCast(d._layerTags).includes(StyleLayers.Background) && (d._raiseWhenDragged === undefined ? Doc.UserDoc()._raiseWhenDragged : d._raiseWhenDragged) && (d.zIndex = zsorted.length + 1 + i); // bringToFront } - this.updateGroupBounds(); - (docDragData.droppedDocuments.length === 1 || de.shiftKey) && this.updateClusterDocs(docDragData.droppedDocuments); return true; } @@ -923,7 +902,9 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P HistoryUtil.pushState(state); } } - SelectionManager.DeselectAll(); + if (SelectionManager.Views().length !== 1 || SelectionManager.Views()[0].Document !== doc) { + SelectionManager.DeselectAll(); + } if (this.props.Document.scrollHeight || this.props.Document.scrollTop !== undefined) { this.props.focus(doc, options); } else { @@ -1236,6 +1217,30 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P { fireImmediately: true, name: "doLayout" }); this._marqueeRef.current?.addEventListener("dashDragAutoScroll", this.onDragAutoScroll as any); + + this._disposers.groupBounds = reaction(() => { + if (this.props.Document._isGroup && this.childDocs.length === this.childDocList?.length) { + const clist = this.childDocs.map(cd => ({ x: NumCast(cd.x), y: NumCast(cd.y), width: cd[WidthSym](), height: cd[HeightSym]() })); + return aggregateBounds(clist, NumCast(this.layoutDoc._xPadding), NumCast(this.layoutDoc._yPadding)); + } + return undefined; + }, + (cbounds) => { + if (cbounds) { + const c = [NumCast(this.layoutDoc.x) + this.layoutDoc[WidthSym]() / 2, NumCast(this.layoutDoc.y) + this.layoutDoc[HeightSym]() / 2]; + const p = [NumCast(this.layoutDoc._panX), NumCast(this.layoutDoc._panY)]; + const pbounds = { + x: (cbounds.x - p[0]) * this.zoomScaling() + c[0], y: (cbounds.y - p[1]) * this.zoomScaling() + c[1], + r: (cbounds.r - p[0]) * this.zoomScaling() + c[0], b: (cbounds.b - p[1]) * this.zoomScaling() + c[1] + }; + this.layoutDoc._width = (pbounds.r - pbounds.x); + this.layoutDoc._height = (pbounds.b - pbounds.y); + this.layoutDoc._panX = (cbounds.r + cbounds.x) / 2; + this.layoutDoc._panY = (cbounds.b + cbounds.y) / 2; + this.layoutDoc.x = pbounds.x; + this.layoutDoc.y = pbounds.y; + } + }, { fireImmediately: true }); } componentWillUnmount() { @@ -1327,8 +1332,10 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P !options && ContextMenu.Instance.addItem({ description: "Options...", subitems: optionItems, icon: "eye" }); const mores = ContextMenu.Instance.findByDescription("More..."); const moreItems = mores && "subitems" in mores ? mores.subitems : []; - moreItems.push({ description: "Export collection", icon: "download", event: async () => Doc.Zip(this.props.Document) }); - moreItems.push({ description: "Import exported collection", icon: "upload", event: ({ x, y }) => this.importDocument(x, y) }); + if (!Doc.UserDoc().noviceMode) { + moreItems.push({ description: "Export collection", icon: "download", event: async () => Doc.Zip(this.props.Document) }); + moreItems.push({ description: "Import exported collection", icon: "upload", event: ({ x, y }) => this.importDocument(x, y) }); + } !mores && ContextMenu.Instance.addItem({ description: "More...", subitems: moreItems, icon: "eye" }); } @@ -1400,6 +1407,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P } chooseGridSpace = (gridSpace: number): number => { + if (!this.zoomScaling()) return 50; const divisions = this.props.PanelWidth() / this.zoomScaling() / gridSpace + 3; return divisions < 60 ? gridSpace : this.chooseGridSpace(gridSpace * 10); } @@ -1484,6 +1492,14 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P return wscale < hscale ? wscale : hscale; } + private groupDropDisposer?: DragManager.DragDropDisposer; + protected createGroupEventsTarget = (ele: HTMLDivElement) => { //used for stacking and masonry view + this.groupDropDisposer?.(); + if (ele) { + this.groupDropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.layoutDoc, this.onInternalPreDrop.bind(this)); + } + } + render() { TraceMobx(); const clientRect = this._mainCont?.getBoundingClientRect(); @@ -1527,7 +1543,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P </div>} {this.props.Document._isGroup && SnappingManager.GetIsDragging() && (this.ChildDrag || this.props.layerProvider?.(this.props.Document) === false) ? - <div className="collectionFreeForm-groupDropper" ref={this.createDashEventsTarget} style={{ + <div className="collectionFreeForm-groupDropper" ref={this.createGroupEventsTarget} style={{ width: this.ChildDrag ? "10000" : "100%", height: this.ChildDrag ? "10000" : "100%", left: this.ChildDrag ? "-5000" : 0, diff --git a/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx b/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx index cedeb1112..1f59f9732 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx @@ -3,20 +3,22 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { Tooltip } from "@material-ui/core"; import { observer } from "mobx-react"; import { unimplementedFunction } from "../../../../Utils"; +import { DocumentType } from "../../../documents/DocumentTypes"; +import { SelectionManager } from "../../../util/SelectionManager"; import { AntimodeMenu, AntimodeMenuProps } from "../../AntimodeMenu"; @observer export class MarqueeOptionsMenu extends AntimodeMenu<AntimodeMenuProps> { static Instance: MarqueeOptionsMenu; - public createCollection: (e: KeyboardEvent | React.PointerEvent | undefined) => void = unimplementedFunction; + public createCollection: (e: KeyboardEvent | React.PointerEvent | undefined, group?: boolean) => void = unimplementedFunction; public delete: (e: KeyboardEvent | React.PointerEvent | undefined) => void = unimplementedFunction; public summarize: (e: KeyboardEvent | React.PointerEvent | undefined) => void = unimplementedFunction; public inkToText: (e: KeyboardEvent | React.PointerEvent | undefined) => void = unimplementedFunction; public showMarquee: () => void = unimplementedFunction; public hideMarquee: () => void = unimplementedFunction; public pinWithView: (e: KeyboardEvent | React.PointerEvent | undefined) => void = unimplementedFunction; - + public isShown = () => this._opacity > 0; constructor(props: Readonly<{}>) { super(props); @@ -26,42 +28,52 @@ export class MarqueeOptionsMenu extends AntimodeMenu<AntimodeMenuProps> { render() { const presPinWithViewIcon = <img src="/assets/pinWithView.png" style={{ margin: "auto", width: 19, transform: 'translate(-2px, -2px)' }} />; const buttons = [ - <Tooltip key="group" title={<><div className="dash-tooltip">Create a Collection</div></>} placement="bottom"> + <Tooltip key="collect" title={<div className="dash-tooltip">Create a Collection</div>} placement="bottom"> <button className="antimodeMenu-button" onPointerDown={this.createCollection}> <FontAwesomeIcon icon="object-group" size="lg" /> </button> </Tooltip>, - <Tooltip key="summarize" title={<><div className="dash-tooltip">Summarize Documents</div></>} placement="bottom"> + <Tooltip key="group" title={<div className="dash-tooltip">Create a Grouping</div>} placement="bottom"> <button className="antimodeMenu-button" - onPointerDown={this.summarize}> - <FontAwesomeIcon icon="compress-arrows-alt" size="lg" /> + onPointerDown={e => this.createCollection(e, true)}> + <FontAwesomeIcon icon="layer-group" size="lg" /> </button> </Tooltip>, - <Tooltip key="delete" title={<><div className="dash-tooltip">Delete Documents</div></>} placement="bottom"> + <Tooltip key="summarize" title={<div className="dash-tooltip">Summarize Documents</div>} placement="bottom"> <button className="antimodeMenu-button" - onPointerDown={this.delete}> - <FontAwesomeIcon icon="trash-alt" size="lg" /> + onPointerDown={this.summarize}> + <FontAwesomeIcon icon="compress-arrows-alt" size="lg" /> </button> </Tooltip>, - <Tooltip key="inkToText" title={<><div className="dash-tooltip">Change to Text</div></>} placement="bottom"> + <Tooltip key="delete" title={<div className="dash-tooltip">Delete Documents</div>} placement="bottom"> <button className="antimodeMenu-button" - onPointerDown={this.inkToText}> - <FontAwesomeIcon icon="font" size="lg" /> + onPointerDown={this.delete}> + <FontAwesomeIcon icon="trash-alt" size="lg" /> </button> </Tooltip>, - <Tooltip key="pinWithView" title={<><div className="dash-tooltip">Pin with selected region</div></>} placement="bottom"> + <Tooltip key="pinWithView" title={<div className="dash-tooltip">Pin with selected region</div>} placement="bottom"> <button className="antimodeMenu-button" onPointerDown={this.pinWithView}> - <>{presPinWithViewIcon}</> + {presPinWithViewIcon} </button> </Tooltip>, ]; + if (false && !SelectionManager.Views().some(v => v.props.Document.type !== DocumentType.INK)) { + buttons.push( + <Tooltip key="inkToText" title={<div className="dash-tooltip">Change to Text</div>} placement="bottom"> + <button + className="antimodeMenu-button" + onPointerDown={this.inkToText}> + <FontAwesomeIcon icon="font" size="lg" /> + </button> + </Tooltip>); + } return this.getElement(buttons); } }
\ No newline at end of file diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaCells.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaCells.tsx index fd99abce5..ed196349e 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaCells.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaCells.tsx @@ -293,12 +293,12 @@ export class CollectionSchemaCell extends React.Component<CellProps> { } } const script = CompileScript(inputSansCommas, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: "number", $c: "number", $: "any" } }); - const changeMade = value.length !== value.length || value.length - 2 !== value.length; + const changeMade = value.length - 2 !== value.length; script.compiled && (retVal = this.applyToDoc(changeMade ? this._rowDoc : this._rowDataDoc, this.props.row, this.props.col, script.run)); // handle booleans } else if (inputIsBool) { const script = CompileScript(value, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: "number", $c: "number", $: "any" } }); - const changeMade = value.length !== value.length || value.length - 2 !== value.length; + const changeMade = value.length - 2 !== value.length; script.compiled && (retVal = this.applyToDoc(changeMade ? this._rowDoc : this._rowDataDoc, this.props.row, this.props.col, script.run)); } } |
