diff options
| author | monoguitari <113245090+monoguitari@users.noreply.github.com> | 2023-08-22 14:15:04 -0400 |
|---|---|---|
| committer | monoguitari <113245090+monoguitari@users.noreply.github.com> | 2023-08-22 14:15:04 -0400 |
| commit | 9293fd8c4128b41b31f9b2214d6799fdff0f2aaa (patch) | |
| tree | 45809c42545b10515f6f88065318b454549dacd1 /src/client/views/collections/collectionFreeForm | |
| parent | 347e8e2bd32854b36828b7bcc645c9c361204251 (diff) | |
| parent | 1c52bd054385d2584bbeae41eecdf9ba6999c25f (diff) | |
Merge branch 'master' into advanced-trails
Diffstat (limited to 'src/client/views/collections/collectionFreeForm')
6 files changed, 151 insertions, 143 deletions
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx index f1d98d22a..fb8ec93b2 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx @@ -235,6 +235,9 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo bActive, textX, textY, + // 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], }; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.scss b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.scss index cb5cef29c..4ada1731f 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.scss +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.scss @@ -1,11 +1,13 @@ -.collectionfreeformlinksview-svgCanvas{ +// TODO: change z-index to -1 when a modal is active? + +.collectionfreeformlinksview-svgCanvas { position: absolute; top: 0; left: 0; - width: 100%; + width: 100%; height: 100%; pointer-events: none; - } - .collectionfreeformlinksview-container { +} +.collectionfreeformlinksview-container { pointer-events: none; - }
\ No newline at end of file +} 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 11151e74e..ffcf0999c 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -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); @@ -418,15 +418,16 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection @undoBatch internalLinkDrop(e: Event, de: DragManager.DropEvent, linkDragData: DragManager.LinkDragData, xp: number, yp: number) { if (linkDragData.linkDragView.props.docViewPath().includes(this.props.docViewPath().lastElement())) { - // dragged document is a child of this collection - if (!linkDragData.linkDragView.props.CollectionFreeFormDocumentView?.() || linkDragData.dragDocument.embedContainer !== this.props.Document) { - // if the source doc view's embedContainer isn't this same freeformcollectionlinkDragData.dragDocument.embedContainer === this.props.Document + let added = false; + // do nothing if link is dropped into any freeform view parent of dragged document + if (!linkDragData.dragDocument.embedContainer || linkDragData.dragDocument.embedContainer !== this.rootDoc) { const source = Docs.Create.TextDocument('', { _width: 200, _height: 75, x: xp, y: yp, title: 'dropped annotation' }); - this.props.addDocument?.(source); + added = this.props.addDocument?.(source) ? true : false; de.complete.linkDocument = DocUtils.MakeLink(linkDragData.linkSourceGetAnchor(), source, { link_relationship: 'annotated by:annotation of' }); // TODODO this is where in text links get passed } - e.stopPropagation(); // do nothing if link is dropped into any freeform view parent of dragged document - return true; + e.stopPropagation(); + !added && e.preventDefault(); + return added; } return false; } @@ -680,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, @@ -1049,10 +1051,10 @@ 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; + const scrollable = NumCast(this.layoutDoc[this.scaleFieldKey], 1) === 1 && docHeight > this.props.PanelHeight() / this.nativeDimScaling + 1e-4; switch (!e.ctrlKey ? Doc.UserDoc().freeformScrollMode : freeformScrollMode.Pan) { case freeformScrollMode.Pan: // if ctrl is selected then zoom @@ -1240,7 +1242,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection }; }; - isContentActive = () => this.props.isSelected() || this.props.isContentActive(); + isContentActive = () => this.props.isContentActive(); @undoBatch @action @@ -1263,13 +1265,15 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection return this.addDocument?.(newDoc); } }; - pointerEvents = () => { + @computed get _pointerEvents() { const engine = this.props.layoutEngine?.() || StrCast(this.props.Document._layoutEngine); const pointerEvents = DocumentDecorations.Instance.Interacting ? 'none' - : this.props.childPointerEvents ?? (this.props.viewDefDivClick || (engine === computePassLayout.name && !this.props.isSelected(true)) ? 'none' : this.props.pointerEvents?.()); + : this.props.childPointerEvents ?? (this.props.viewDefDivClick || (engine === computePassLayout.name && !this.props.isSelected(true)) || this.isContentActive() === false ? 'none' : this.props.pointerEvents?.()); return pointerEvents; - }; + } + pointerEvents = () => this._pointerEvents; + childContentsActive = () => (this.props.childContentsActive ?? this.isContentActive() === false ? returnFalse : emptyFunction)(); getChildDocView(entry: PoolData) { const childLayout = entry.pair.layout; const childData = entry.pair.data; @@ -1297,8 +1301,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection childFilters={this.childDocFilters} childFiltersByRanges={this.childDocRangeFilters} searchFilterDocs={this.searchFilterDocs} - isDocumentActive={this.props.childDocumentsActive?.() ? this.props.isDocumentActive : this.isContentActive} - isContentActive={this.props.childContentsActive ?? emptyFunction} + isDocumentActive={this.props.childDocumentsActive?.() || this.rootDoc._isGroup ? this.props.isDocumentActive : this.isContentActive} + isContentActive={this.childContentsActive} focus={this.Document._isGroup ? this.groupFocus : this.isAnnotationOverlay ? this.props.focus : this.focus} addDocTab={this.addDocTab} addDocument={this.props.addDocument} @@ -1308,16 +1312,14 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged} docViewPath={this.props.docViewPath} styleProvider={this.getClusterColor} - canEmbedOnDrag={this.props.childCanEmbedOnDrag} + dragAction={(this.rootDoc.childDragAction ?? this.props.childDragAction) as dropActionType} dataProvider={this.childDataProvider} sizeProvider={this.childSizeProvider} - dropAction={StrCast(this.props.Document.childDropAction) as dropActionType} bringToFront={this.bringToFront} layout_showTitle={this.props.childlayout_showTitle} dontRegisterView={this.props.dontRenderDocuments || this.props.dontRegisterView} pointerEvents={this.pointerEvents} - //rotation={this.props.styleProvider?.(childLayout, this.props, StyleProp.JitterRotation) || 0} - //fitContentsToBox={this.props.fitContentsToBox || BoolCast(this.props.treeViewFreezeChildDimensions)} // bcz: check this + //fitContentsToBox={this.props.fitContentsToBox || BoolCast(this.props.treeView_FreezeChildDimensions)} // bcz: check this /> ); } @@ -1356,6 +1358,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection @observable _lightboxDoc: Opt<Doc>; getCalculatedPositions(params: { pair: { layout: Doc; data?: Doc }; index: number; collection: Doc }): PoolData { + const random = (min: number, max: number, x: number, y: number) => /* min should not be equal to max */ min + (((Math.abs(x * y) * 9301 + 49297) % 233280) / 233280) * (max - min); const childDoc = params.pair.layout; const childDocLayout = Doc.Layout(childDoc); const layoutFrameNumber = Cast(this.Document._currentFrame, 'number'); // frame number that container is at which determines layout frame values @@ -1366,11 +1369,15 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection layoutFrameNumber === undefined ? { _width: Cast(childDocLayout._width, 'number'), _height: Cast(childDocLayout._height, 'number'), _rotation: Cast(childDocLayout._rotation, 'number'), x: childDoc.x, y: childDoc.y, opacity: this.props.childOpacity?.() } : CollectionFreeFormDocumentView.getValues(childDoc, layoutFrameNumber); + // prettier-ignore + const rotation = Cast(_rotation,'number', + !this.layoutDoc._rotation_jitter ? null + : NumCast(this.layoutDoc._rotation_jitter) * random(-1, 1, NumCast(x), NumCast(y)) ); return { x: Number.isNaN(NumCast(x)) ? 0 : NumCast(x), y: Number.isNaN(NumCast(y)) ? 0 : NumCast(y), z: Cast(z, 'number'), - rotation: Cast(_rotation, 'number'), + rotation: rotation, color: Cast(color, 'string') ? StrCast(color) : this.props.styleProvider?.(childDoc, this.props, StyleProp.Color), backgroundColor: Cast(backgroundColor, 'string') ? StrCast(backgroundColor) : this.getClusterColor(childDoc, this.props, StyleProp.BackgroundColor), opacity: !_width ? 0 : this._keyframeEditing ? 1 : Cast(opacity, 'number') ?? this.props.styleProvider?.(childDoc, this.props, StyleProp.Opacity), @@ -1435,21 +1442,17 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection }.bind(this) ); - childPositionProviderUnmemoized = (doc: Doc, replica: string) => { - return this._layoutPoolData.get(doc[Id] + (replica || '')); - }; + childPositionProviderUnmemoized = (doc: Doc, replica: string) => this._layoutPoolData.get(doc[Id] + (replica || '')); childDataProvider = computedFn( function childDataProvider(this: any, doc: Doc, replica: string) { - return this._layoutPoolData.get(doc[Id] + (replica || '')); + return this.childPositionProviderUnmemoized(doc, replica); }.bind(this) ); - childSizeProviderUnmemoized = (doc: Doc, replica: string) => { - return this._layoutSizeData.get(doc[Id] + (replica || '')); - }; + childSizeProviderUnmemoized = (doc: Doc, replica: string) => this._layoutSizeData.get(doc[Id] + (replica || '')); childSizeProvider = computedFn( function childSizeProvider(this: any, doc: Doc, replica: string) { - return this._layoutSizeData.get(doc[Id] + (replica || '')); + return this.childSizeProviderUnmemoized(doc, replica); }.bind(this) ); @@ -1535,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.CollectionConfigDocument({ 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) { @@ -1864,6 +1867,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 ( @@ -1906,13 +1910,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} @@ -1943,19 +1947,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); @@ -1987,7 +1991,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection onDragOver={e => e.preventDefault()} onContextMenu={this.onContextMenu} style={{ - pointerEvents: SnappingManager.GetIsDragging() && this.childDocs.includes(DragManager.docsBeingDragged.lastElement()) ? 'all' : (this.props.pointerEvents?.() as any), + pointerEvents: this.props.isContentActive() && SnappingManager.GetIsDragging() ? 'all' : (this.props.pointerEvents?.() as any), textAlign: this.isAnnotationOverlay ? 'initial' : undefined, transform: `scale(${this.nativeDimScaling || 1})`, width: `${100 / (this.nativeDimScaling || 1)}%`, @@ -2082,7 +2086,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 @@ -2154,6 +2158,7 @@ class CollectionFreeFormViewPannableContents extends React.Component<CollectionF } render() { + const brushedView = this.props.brushedView(); return ( <div className={'collectionfreeformview' + (this.props.viewDefDivClick ? '-viewDef' : '-none')} @@ -2171,21 +2176,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> ); @@ -2256,22 +2258,20 @@ class CollectionFreeFormBackgroundGrid extends React.Component<CollectionFreeFor export function CollectionBrowseClick(dv: DocumentView, clientX: number, clientY: number) { const browseTransitionTime = 500; SelectionManager.DeselectAll(); - if ( - dv.props.focus(dv.props.Document, { - willZoomCentered: true, - zoomScale: 0.8, - zoomTime: browseTransitionTime, - }) === undefined - ) { - const selfFfview = !dv.rootDoc._isGroup && dv.ComponentView instanceof CollectionFreeFormView ? dv.ComponentView : undefined; - let parFfview = dv.props.CollectionFreeFormDocumentView?.().props.CollectionFreeFormView; - while (parFfview?.rootDoc._isGroup) parFfview = parFfview.props.CollectionFreeFormDocumentView?.().props.CollectionFreeFormView; - const ffview = selfFfview && selfFfview.rootDoc[selfFfview.scaleFieldKey] !== 0.5 ? selfFfview : parFfview; // if focus doc is a freeform that is not at it's default 0.5 scale, then zoom out on it. Otherwise, zoom out on the parent ffview - ffview?.zoomSmoothlyAboutPt(ffview.getTransform().transformPoint(clientX, clientY), 0.5, browseTransitionTime); - Doc.linkFollowHighlight(dv?.props.Document, false); - } else { - DocumentManager.Instance.showDocument(dv.rootDoc, { zoomScale: 0.8, willZoomCentered: true }); - } + DocumentManager.Instance.showDocument(dv.rootDoc, { zoomScale: 0.8, willZoomCentered: true }, (focused: boolean) => { + if (!focused) { + const selfFfview = !dv.rootDoc._isGroup && dv.ComponentView instanceof CollectionFreeFormView ? dv.ComponentView : undefined; + let containers = dv.props.docViewPath(); + let parFfview = dv.props.CollectionFreeFormDocumentView?.().props.CollectionFreeFormView; + for (var cont of containers) { + parFfview = parFfview ?? cont.props.CollectionFreeFormDocumentView?.().props.CollectionFreeFormView; + } + while (parFfview?.rootDoc._isGroup) parFfview = parFfview.props.CollectionFreeFormDocumentView?.().props.CollectionFreeFormView; + const ffview = selfFfview && selfFfview.rootDoc[selfFfview.scaleFieldKey] !== 0.5 ? selfFfview : parFfview; // if focus doc is a freeform that is not at it's default 0.5 scale, then zoom out on it. Otherwise, zoom out on the parent ffview + ffview?.zoomSmoothlyAboutPt(ffview.getTransform().transformPoint(clientX, clientY), 0.5, browseTransitionTime); + Doc.linkFollowHighlight(dv?.props.Document, false); + } + }); } ScriptingGlobals.add(CollectionBrowseClick); ScriptingGlobals.add(function nextKeyFrame(readOnly: boolean) { diff --git a/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx b/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx index c9168d40a..0f51fe6ff 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx @@ -4,6 +4,10 @@ import { Tooltip } from '@material-ui/core'; import { observer } from 'mobx-react'; import { unimplementedFunction } from '../../../../Utils'; import { AntimodeMenu, AntimodeMenuProps } from '../../AntimodeMenu'; +import { IconButton } from 'browndash-components'; +import { StrCast } from '../../../../fields/Types'; +import { Doc } from '../../../../fields/Doc'; +import { computed } from 'mobx'; @observer export class MarqueeOptionsMenu extends AntimodeMenu<AntimodeMenuProps> { @@ -22,39 +26,44 @@ export class MarqueeOptionsMenu extends AntimodeMenu<AntimodeMenuProps> { MarqueeOptionsMenu.Instance = this; } + @computed get userColor() { + return StrCast(Doc.UserDoc().userColor) + } + render() { - const presPinWithViewIcon = <img src="/assets/pinWithView.png" style={{ margin: 'auto', width: 19, transform: 'translate(-2px, -2px)' }} />; + const presPinWithViewIcon = <img src="/assets/pinWithView.png" style={{ width: 19 }} />; const buttons = ( <> - <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="group" title={<div className="dash-tooltip">Create a Grouping</div>} placement="bottom"> - <button className="antimodeMenu-button" onPointerDown={e => this.createCollection(e, true)}> - <FontAwesomeIcon icon="layer-group" size="lg" /> - </button> - </Tooltip> - , - <Tooltip key="summarize" title={<div className="dash-tooltip">Summarize Documents</div>} placement="bottom"> - <button className="antimodeMenu-button" onPointerDown={this.summarize}> - <FontAwesomeIcon icon="compress-arrows-alt" size="lg" /> - </button> - </Tooltip> - , - <Tooltip key="delete" title={<div className="dash-tooltip">Delete Documents</div>} placement="bottom"> - <button className="antimodeMenu-button" onPointerDown={this.delete}> - <FontAwesomeIcon icon="trash-alt" size="lg" /> - </button> - </Tooltip> - , - <Tooltip key="pinWithView" title={<div className="dash-tooltip">Pin selected region to trail</div>} placement="bottom"> - <button className="antimodeMenu-button" onPointerDown={this.pinWithView}> - {presPinWithViewIcon} - </button> - </Tooltip> + <IconButton + tooltip={"Create a Collection"} + onPointerDown={this.createCollection} + icon={<FontAwesomeIcon icon="object-group"/>} + color={this.userColor} + /> + <IconButton + tooltip={"Create a Grouping"} + onPointerDown={e => this.createCollection(e, true)} + icon={<FontAwesomeIcon icon="layer-group"/>} + color={this.userColor} + /> + <IconButton + tooltip={"Summarize Documents"} + onPointerDown={this.summarize} + icon={<FontAwesomeIcon icon="compress-arrows-alt"/>} + color={this.userColor} + /> + <IconButton + tooltip={"Delete Documents"} + onPointerDown={this.delete} + icon={<FontAwesomeIcon icon="trash-alt"/>} + color={this.userColor} + /> + <IconButton + tooltip={"Pin selected region"} + onPointerDown={this.pinWithView} + icon={presPinWithViewIcon} + color={this.userColor} + /> </> ); return this.getElement(buttons); diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 534275610..1c3da1dc5 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -9,7 +9,7 @@ import { RichTextField } from '../../../../fields/RichTextField'; import { SchemaHeaderField } from '../../../../fields/SchemaHeaderField'; import { Cast, DocCast, FieldValue, NumCast, StrCast } from '../../../../fields/Types'; import { ImageField } from '../../../../fields/URLField'; -import { GetEffectiveAcl } from '../../../../fields/util'; +import { distributeAcls, GetEffectiveAcl, SharingPermissions } from '../../../../fields/util'; import { intersectRect, returnFalse, Utils } from '../../../../Utils'; import { CognitiveServices } from '../../../cognitive_services/CognitiveServices'; import { Docs, DocumentOptions, DocUtils } from '../../../documents/Documents'; @@ -161,7 +161,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque }); }) ); - } else if (e.key === 's' && e.ctrlKey) { + } /* else if (e.key === 's' && e.ctrlKey) { e.preventDefault(); const slide = DocUtils.copyDragFactory(DocCast(Doc.UserDoc().emptySlide))!; slide.x = x; @@ -170,6 +170,14 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque TreeView._editTitleOnLoad = { id: slide[Id], parent: undefined }; this.props.addDocument?.(slide); e.stopPropagation(); + }*/ 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'); @@ -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 @@ -337,7 +327,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque @action onClick = (e: React.MouseEvent): void => { if (this.props.pointerEvents?.() === 'none') return; - if (Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD && Math.abs(e.clientY - this._downY) < Utils.DRAG_THRESHOLD) { + if (Utils.isClick(e.clientX, e.clientY, this._downX, this._downY, Date.now())) { if (Doc.ActiveTool === InkTool.None) { if (!(e.nativeEvent as any).marqueeHit) { (e.nativeEvent as any).marqueeHit = true; @@ -377,7 +367,6 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque : ((doc: Doc) => { Doc.GetProto(doc).data = new List<Doc>(selected); Doc.GetProto(doc).title = makeGroup ? 'grouping' : 'nested freeform'; - !this.props.isAnnotationOverlay && Doc.AddFileOrphan(Doc.GetProto(doc)); doc._freeform_panX = doc._freeform_panY = 0; return doc; })(Doc.MakeCopy(Doc.UserDoc().emptyCollection as Doc, true)); @@ -385,12 +374,12 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque newCollection._width = this.Bounds.width; newCollection._height = this.Bounds.height; newCollection._isGroup = makeGroup; + newCollection._dragWhenActive = makeGroup; newCollection.forceActive = makeGroup; - newCollection.enableDragWhenActive = makeGroup; newCollection.x = this.Bounds.left; newCollection.y = this.Bounds.top; newCollection.layout_fitWidth = true; - selected.forEach(d => (d.embedContainer = newCollection)); + selected.forEach(d => Doc.SetContainer(d, newCollection)); this.hideMarquee(); return newCollection; }); |
