diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Utils.ts | 2 | ||||
-rw-r--r-- | src/client/documents/Documents.ts | 4 | ||||
-rw-r--r-- | src/client/util/DragManager.ts | 9 | ||||
-rw-r--r-- | src/client/views/DashboardView.tsx | 1 | ||||
-rw-r--r-- | src/client/views/DocumentDecorations.tsx | 12 | ||||
-rw-r--r-- | src/client/views/GlobalKeyHandler.ts | 46 | ||||
-rw-r--r-- | src/client/views/PreviewCursor.tsx | 21 | ||||
-rw-r--r-- | src/client/views/PropertiesButtons.tsx | 2 | ||||
-rw-r--r-- | src/client/views/collections/CollectionCarousel3DView.scss | 14 | ||||
-rw-r--r-- | src/client/views/collections/CollectionCarousel3DView.tsx | 32 | ||||
-rw-r--r-- | src/client/views/global/globalCssVariables.scss | 7 | ||||
-rw-r--r-- | src/client/views/global/globalCssVariables.scss.d.ts | 3 | ||||
-rw-r--r-- | src/client/views/nodes/ComparisonBox.tsx | 12 | ||||
-rw-r--r-- | src/client/views/nodes/DocumentView.tsx | 2 | ||||
-rw-r--r-- | src/fields/Doc.ts | 28 |
15 files changed, 102 insertions, 93 deletions
diff --git a/src/Utils.ts b/src/Utils.ts index 73de6d754..f2ad814d4 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -540,7 +540,7 @@ export function returnNone() { } export function returnVal(val1?: number, val2?: number) { - return val1 !== undefined ? val1 : val2 !== undefined ? val2 : 0; + return val1 ? val1 : val2 !== undefined ? val2 : 0; } export function returnOne() { diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 966cd6a68..3be476e68 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -1195,12 +1195,14 @@ export namespace Docs { }, ], }; - return DockDocument( + const doc = DockDocument( configs.map(c => c.doc), JSON.stringify(layoutConfig), options, id ); + configs.map(c => (c.doc.embedContainer = doc)); + return doc; } export function DelegateDocument(proto: Doc, options: DocumentOptions = {}) { diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index c8bc26b93..fb4a8985c 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -174,6 +174,13 @@ export namespace DragManager { userDropAction: dropActionType; } + let defaultPreDropFunc = (e: Event, de: DragManager.DropEvent, targetAction: dropActionType) => { + if (de.complete.docDragData) { + targetAction && (de.complete.docDragData.dropAction = targetAction); + e.stopPropagation(); + } + }; + export function MakeDropTarget(element: HTMLElement, dropFunc: (e: Event, de: DropEvent) => void, doc?: Doc, preDropFunc?: (e: Event, de: DropEvent, targetAction: dropActionType) => void): DragDropDisposer { if ('canDrop' in element.dataset) { throw new Error("Element is already droppable, can't make it droppable again"); @@ -182,7 +189,7 @@ export namespace DragManager { const handler = (e: Event) => dropFunc(e, (e as CustomEvent<DropEvent>).detail); const preDropHandler = (e: Event) => { const de = (e as CustomEvent<DropEvent>).detail; - preDropFunc?.(e, de, StrCast(doc?.targetDropAction) as dropActionType); + (preDropFunc ?? defaultPreDropFunc)(e, de, StrCast(doc?.targetDropAction) as dropActionType); }; element.addEventListener('dashOnDrop', handler); doc && element.addEventListener('dashPreDrop', preDropHandler); diff --git a/src/client/views/DashboardView.tsx b/src/client/views/DashboardView.tsx index b51c77cb2..fb41ca8af 100644 --- a/src/client/views/DashboardView.tsx +++ b/src/client/views/DashboardView.tsx @@ -366,7 +366,6 @@ export class DashboardView extends React.Component { const title = name ? name : `Dashboard ${dashboardCount}`; const freeformDoc = Doc.GuestTarget || Docs.Create.FreeformDocument([], freeformOptions); const dashboardDoc = Docs.Create.StandardCollectionDockingDocument([{ doc: freeformDoc, initialWidth: 600 }], { title: title }, id, 'row'); - freeformDoc.embedContainer = dashboardDoc; // switching the tabs from the datadoc to the regular doc const dashboardTabs = DocListCast(dashboardDoc[DataSym].data); diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index beddc0e8a..72c6d449a 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -189,7 +189,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P @action onBackgroundMove = (dragTitle: boolean, e: PointerEvent): boolean => { const dragDocView = SelectionManager.Views()[0]; - const containers = new Set<Doc|undefined>(); + const containers = new Set<Doc | undefined>(); SelectionManager.Views().forEach(v => containers.add(DocCast(v.rootDoc.embedContainer))); if (containers.size > 1) return false; const { left, top } = dragDocView.getBounds() || { left: 0, top: 0 }; @@ -274,19 +274,19 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P if (selectedDocs.length) { if (e.ctrlKey) { // open an embedding in a new tab with Ctrl Key - CollectionDockingView.AddSplit(Doc.BestEmbedding(selectedDocs[0].props.Document), OpenWhereMod.right); + CollectionDockingView.AddSplit(Doc.BestEmbedding(selectedDocs[0].rootDoc), OpenWhereMod.right); } else if (e.shiftKey) { // open centered in a new workspace with Shift Key - const embedding = Doc.MakeEmbedding(selectedDocs[0].props.Document); + const embedding = Doc.MakeEmbedding(selectedDocs[0].rootDoc); embedding.embedContainer = undefined; embedding.x = -embedding[WidthSym]() / 2; embedding.y = -embedding[HeightSym]() / 2; CollectionDockingView.AddSplit(Docs.Create.FreeformDocument([embedding], { title: 'Tab for ' + embedding.title }), OpenWhereMod.right); } else if (e.altKey) { // open same document in new tab - CollectionDockingView.ToggleSplit(selectedDocs[0].props.Document, OpenWhereMod.right); + CollectionDockingView.ToggleSplit(selectedDocs[0].rootDoc, OpenWhereMod.right); } else { - var openDoc = selectedDocs[0].props.Document; + var openDoc = selectedDocs[0].rootDoc; if (openDoc.layout_fieldKey === 'layout_icon') { openDoc = DocListCast(openDoc.proto_embeddings).find(embedding => !embedding.embedContainer) ?? Doc.MakeEmbedding(openDoc); Doc.deiconifyView(openDoc); @@ -294,7 +294,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P LightboxView.SetLightboxDoc( openDoc, undefined, - selectedDocs.slice(1).map(view => view.props.Document) + selectedDocs.slice(1).map(view => view.rootDoc) ); } } diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts index 625bc760d..9a78eb9fc 100644 --- a/src/client/views/GlobalKeyHandler.ts +++ b/src/client/views/GlobalKeyHandler.ts @@ -1,22 +1,19 @@ import { random } from 'lodash'; import { action, runInAction } from 'mobx'; -import { DateField } from '../../fields/DateField'; import { Doc, DocListCast } from '../../fields/Doc'; import { Id } from '../../fields/FieldSymbols'; import { InkTool } from '../../fields/InkField'; -import { List } from '../../fields/List'; import { ScriptField } from '../../fields/ScriptField'; -import { Cast, PromiseValue } from '../../fields/Types'; +import { Cast, DocCast, NumCast, PromiseValue } from '../../fields/Types'; import { GoogleAuthenticationManager } from '../apis/GoogleAuthenticationManager'; import { DocServer } from '../DocServer'; -import { DocumentType } from '../documents/DocumentTypes'; import { DragManager } from '../util/DragManager'; import { GroupManager } from '../util/GroupManager'; import { SelectionManager } from '../util/SelectionManager'; import { SettingsManager } from '../util/SettingsManager'; import { SharingManager } from '../util/SharingManager'; import { SnappingManager } from '../util/SnappingManager'; -import { undoBatch, UndoManager } from '../util/UndoManager'; +import { undoable, UndoManager } from '../util/UndoManager'; import { CollectionDockingView } from './collections/CollectionDockingView'; import { CollectionFreeFormView } from './collections/collectionFreeForm'; import { CollectionFreeFormViewChrome } from './collections/CollectionMenu'; @@ -350,38 +347,13 @@ export class KeyManager { }); public paste(e: ClipboardEvent) { - const plain = e.clipboardData?.getData('text/plain'); - const clone = plain?.startsWith('__DashCloneId('); - if (plain && (plain.startsWith('__DashDocId(') || clone)) { - const first = SelectionManager.Views().length ? SelectionManager.Views()[0] : undefined; - if (first?.props.Document.type === DocumentType.COL) { - const docids = plain.split(':'); - let count = 1; - const list: Doc[] = []; - const targetDataDoc = Doc.GetProto(first.props.Document); - const fieldKey = first.LayoutFieldKey; - const docList = DocListCast(targetDataDoc[fieldKey]); - docids.map( - (did, i) => - i && - DocServer.GetRefField(did).then(async doc => { - count++; - if (doc instanceof Doc) { - list.push(doc); - } - if (count === docids.length) { - const added = await Promise.all(list.filter(d => !docList.includes(d)).map(async d => (clone ? (await Doc.MakeClone(d, true)).clone : d))); - if (added.length) { - added.map(doc => (doc.embedContainer = targetDataDoc)); - undoBatch(() => { - targetDataDoc[fieldKey] = new List<Doc>([...docList, ...added]); - targetDataDoc[fieldKey + '_modificationDate'] = new DateField(new Date(Date.now())); - })(); - } - } - }) - ); - } + const plain = e.clipboardData?.getData('text/plain'); // list of document ids, separated by ':'s + if (!plain) return; + const clone = plain.startsWith('__DashCloneId('); + const docids = plain.split(':'); // hack! docids[0] is the top left of the selection rectangle + const addDocument = SelectionManager.Views().lastElement()?.ComponentView?.addDocument; + if (addDocument && (plain.startsWith('__DashDocId(') || clone)) { + Doc.Paste(docids.slice(1), clone, addDocument); } } diff --git a/src/client/views/PreviewCursor.tsx b/src/client/views/PreviewCursor.tsx index f7fb443c0..8dd13ff08 100644 --- a/src/client/views/PreviewCursor.tsx +++ b/src/client/views/PreviewCursor.tsx @@ -1,14 +1,15 @@ import { action, observable, runInAction } from 'mobx'; import { observer } from 'mobx-react'; +import { listenerCount } from 'process'; import * as React from 'react'; import { Doc } from '../../fields/Doc'; -import { Cast, NumCast, StrCast } from '../../fields/Types'; +import { Cast, DocCast, NumCast, StrCast } from '../../fields/Types'; import { returnFalse } from '../../Utils'; import { DocServer } from '../DocServer'; import { Docs, DocumentOptions, DocUtils } from '../documents/Documents'; import { ImageUtils } from '../util/Import & Export/ImageUtils'; import { Transform } from '../util/Transform'; -import { undoBatch, UndoManager } from '../util/UndoManager'; +import { undoable, undoBatch, UndoManager } from '../util/UndoManager'; import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox'; import './PreviewCursor.scss'; @@ -66,23 +67,11 @@ export class PreviewCursor extends React.Component<{}> { } else if (plain.startsWith('__DashDocId(') || plain.startsWith('__DashCloneId(')) { const clone = plain.startsWith('__DashCloneId('); const docids = plain.split(':'); - const strs = docids[0].split(','); + const strs = docids[0].split(','); // hack! docids[0] is the top left of the selection rectangle const ptx = Number(strs[0].substring((clone ? '__DashCloneId(' : '__DashDocId(').length)); const pty = Number(strs[1].substring(0, strs[1].length - 1)); + Doc.Paste(docids.slice(1), clone, PreviewCursor._addDocument, ptx, pty, newPoint); - const batch = UndoManager.StartBatch('cloning'); - { - const toCopy = await Promise.all(docids.slice(1).map(async did => Cast(await DocServer.GetRefField(did), Doc, null))); - const docs = clone ? (await Promise.all(Doc.MakeClones(toCopy, false))).map(res => res.clone) : toCopy; - const firstx = docs.length ? NumCast(docs[0].x) + ptx - newPoint[0] : 0; - const firsty = docs.length ? NumCast(docs[0].y) + pty - newPoint[1] : 0; - docs.map(doc => { - doc.x = NumCast(doc.x) - firstx; - doc.y = NumCast(doc.y) - firsty; - }); - PreviewCursor._addDocument(docs); - } - batch.end(); e.stopPropagation(); } else { FormattedTextBox.PasteOnLoad = e; diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx index a5c58c9d2..49e8ed369 100644 --- a/src/client/views/PropertiesButtons.tsx +++ b/src/client/views/PropertiesButtons.tsx @@ -414,7 +414,7 @@ export class PropertiesButtons extends React.Component<{}, {}> { {toggle(this.onClickButton)} {toggle(this.layout_fitWidthButton)} {toggle(this.freezeThumb)} - {toggle(this.forceActiveButton, { display: !isFreeForm && !isMap ? 'none' : '' })} + {toggle(this.forceActiveButton)} {toggle(this.fitContentButton, { display: !isFreeForm && !isMap ? 'none' : '' })} {toggle(this.isLightboxButton, { display: !isFreeForm && !isMap ? 'none' : '' })} {toggle(this.layout_autoHeightButton, { display: !isText && !isStacking && !isTree ? 'none' : '' })} diff --git a/src/client/views/collections/CollectionCarousel3DView.scss b/src/client/views/collections/CollectionCarousel3DView.scss index 5c8b491eb..6bd1d9f5f 100644 --- a/src/client/views/collections/CollectionCarousel3DView.scss +++ b/src/client/views/collections/CollectionCarousel3DView.scss @@ -1,3 +1,4 @@ +@import '../global/globalCssVariables'; .collectionCarousel3DView-outer { height: 100%; position: relative; @@ -7,8 +8,8 @@ .carousel-wrapper { display: flex; position: absolute; - top: 15%; - height: 60%; + top: $CAROUSEL3D_TOP * 1%; + height: ($CAROUSEL3D_SIDE_SCALE * 100) * 1%; align-items: center; transition: transform 0.3s cubic-bezier(0.455, 0.03, 0.515, 0.955); @@ -17,10 +18,17 @@ flex: 1; transition: opacity 0.3s linear, transform 0.5s cubic-bezier(0.455, 0.03, 0.515, 0.955); pointer-events: none; + opacity: 0.5; + z-index: 1; + transform: scale($CAROUSEL3D_SIDE_SCALE); + user-select: none; } .collectionCarousel3DView-item-active { pointer-events: unset; + opacity: 1; + z-index: 2; + transform: scale($CAROUSEL3D_CENTER_SCALE); } } @@ -105,4 +113,4 @@ .carousel3DView-back-scroll:hover, .carousel3DView-fwd-scroll:hover { background: lightgray; -}
\ No newline at end of file +} diff --git a/src/client/views/collections/CollectionCarousel3DView.tsx b/src/client/views/collections/CollectionCarousel3DView.tsx index b10b453bf..d94e552b4 100644 --- a/src/client/views/collections/CollectionCarousel3DView.tsx +++ b/src/client/views/collections/CollectionCarousel3DView.tsx @@ -7,6 +7,8 @@ import { Id } from '../../../fields/FieldSymbols'; import { NumCast, ScriptCast, StrCast } from '../../../fields/Types'; import { returnFalse, returnZero, Utils } from '../../../Utils'; import { DragManager } from '../../util/DragManager'; +import { SelectionManager } from '../../util/SelectionManager'; +import { CAROUSEL3D_CENTER_SCALE, CAROUSEL3D_SIDE_SCALE, CAROUSEL3D_TOP } from '../global/globalCssVariables.scss'; import { DocumentView } from '../nodes/DocumentView'; import { StyleProp } from '../StyleProvider'; import './CollectionCarousel3DView.scss'; @@ -32,11 +34,17 @@ export class CollectionCarousel3DView extends CollectionSubView() { } }; + centerScale = Number(CAROUSEL3D_CENTER_SCALE); panelWidth = () => this.props.PanelWidth() / 3; - panelHeight = () => this.props.PanelHeight() * 0.6; + panelHeight = () => this.props.PanelHeight() * Number(CAROUSEL3D_SIDE_SCALE); onChildDoubleClick = () => ScriptCast(this.layoutDoc.onChildDoubleClick); isContentActive = () => this.props.isSelected() || this.props.isContentActive() || this.props.isAnyChildContentActive(); isChildContentActive = () => (this.isContentActive() ? true : false); + childScreenToLocal = () => + this.props // document's left is the panel shifted by the doc's index * panelWidth/#docs. But it scales by centerScale around its center, so it's left moves left by the distance of the left from the center (panelwidth/2) * the scale delta (centerScale-1) + .ScreenToLocalTransform() // the top behaves the same way ecept it's shifted by the 'top' amount specified for the panel in css and then by the scale factor. + .translate(-this.panelWidth() + ((this.centerScale - 1) * this.panelWidth()) / 2, -((Number(CAROUSEL3D_TOP) / 100) * this.props.PanelHeight()) + ((this.centerScale - 1) * this.panelHeight()) / 2) + .scale(1 / this.centerScale); @computed get content() { const currentIndex = NumCast(this.layoutDoc._carousel_index); @@ -46,13 +54,14 @@ export class CollectionCarousel3DView extends CollectionSubView() { {...this.props} NativeWidth={returnZero} NativeHeight={returnZero} - suppressSetHeight={true} + //suppressSetHeight={true} onDoubleClick={this.onChildDoubleClick} renderDepth={this.props.renderDepth + 1} LayoutTemplate={this.props.childLayoutTemplate} LayoutTemplateString={this.props.childLayoutString} Document={childPair.layout} DataDoc={childPair.data} + ScreenToLocalTransform={this.childScreenToLocal} isContentActive={this.isChildContentActive} isDocumentActive={this.props.childDocumentsActive?.() || this.Document._childDocumentsActive ? this.props.isDocumentActive : this.isContentActive} PanelWidth={this.panelWidth} @@ -64,10 +73,7 @@ export class CollectionCarousel3DView extends CollectionSubView() { return this.childLayoutPairs.map((childPair, index) => { return ( - <div - key={childPair.layout[Id]} - className={`collectionCarousel3DView-item${index === currentIndex ? '-active' : ''} ${index}`} - style={index === currentIndex ? { opacity: '1', transform: 'scale(1.3)', width: this.panelWidth() } : { opacity: '0.5', transform: 'scale(0.6)', userSelect: 'none', width: this.panelWidth() }}> + <div key={childPair.layout[Id]} className={`collectionCarousel3DView-item${index === currentIndex ? '-active' : ''} ${index}`} style={{ width: this.panelWidth() }}> {displayDoc(childPair)} </div> ); @@ -75,6 +81,7 @@ export class CollectionCarousel3DView extends CollectionSubView() { } changeSlide = (direction: number) => { + SelectionManager.DeselectAll(); this.layoutDoc._carousel_index = (NumCast(this.layoutDoc._carousel_index) + direction + this.childLayoutPairs.length) % this.childLayoutPairs.length; }; @@ -114,10 +121,10 @@ export class CollectionCarousel3DView extends CollectionSubView() { return ( <div className="arrow-buttons"> <div key="back" className="carousel3DView-back" style={{ background: `${StrCast(this.props.Document.backgroundColor)}` }} onClick={e => this.onArrowClick(e, -1)}> - <FontAwesomeIcon icon={'angle-left'} size={'2x'} /> + <FontAwesomeIcon icon="angle-left" size={'2x'} /> </div> <div key="fwd" className="carousel3DView-fwd" style={{ background: `${StrCast(this.props.Document.backgroundColor)}` }} onClick={e => this.onArrowClick(e, 1)}> - <FontAwesomeIcon icon={'angle-right'} size={'2x'} /> + <FontAwesomeIcon icon="angle-right" size={'2x'} /> </div> {this.autoScrollButton} </div> @@ -141,11 +148,12 @@ export class CollectionCarousel3DView extends CollectionSubView() { @computed get dots() { return this.childLayoutPairs.map((_child, index) => <div key={Utils.GenerateGuid()} className={`dot${index === NumCast(this.layoutDoc._carousel_index) ? '-active' : ''}`} onClick={() => (this.layoutDoc._carousel_index = index)} />); } - - render() { + @computed get translateX() { const index = NumCast(this.layoutDoc._carousel_index); - const translateX = this.panelWidth() * (1 - index); + return this.panelWidth() * (1 - index); + } + render() { return ( <div className="collectionCarousel3DView-outer" @@ -154,7 +162,7 @@ export class CollectionCarousel3DView extends CollectionSubView() { background: this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BackgroundColor), color: this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.Color), }}> - <div className="carousel-wrapper" style={{ transform: `translateX(${translateX}px)` }}> + <div className="carousel-wrapper" style={{ transform: `translateX(${this.translateX}px)` }}> {this.content} </div> {this.props.Document._chromeHidden ? null : this.buttons} diff --git a/src/client/views/global/globalCssVariables.scss b/src/client/views/global/globalCssVariables.scss index 3496bb835..422dae15b 100644 --- a/src/client/views/global/globalCssVariables.scss +++ b/src/client/views/global/globalCssVariables.scss @@ -70,6 +70,10 @@ $DFLT_IMAGE_NATIVE_DIM: 900px; $LEFT_MENU_WIDTH: 60px; $TREE_BULLET_WIDTH: 20px; +$CAROUSEL3D_CENTER_SCALE: 1.3; +$CAROUSEL3D_SIDE_SCALE: 0.3; +$CAROUSEL3D_TOP: 15; + :export { contextMenuZindex: $contextMenu-zindex; SCHEMA_DIVIDER_WIDTH: $SCHEMA_DIVIDER_WIDTH; @@ -84,4 +88,7 @@ $TREE_BULLET_WIDTH: 20px; TREE_BULLET_WIDTH: $TREE_BULLET_WIDTH; INK_MASK_SIZE: $INK_MASK_SIZE; MEDIUM_GRAY: $medium-gray; + CAROUSEL3D_CENTER_SCALE: $CAROUSEL3D_CENTER_SCALE; + CAROUSEL3D_SIDE_SCALE: $CAROUSEL3D_SIDE_SCALE; + CAROUSEL3D_TOP: $CAROUSEL3D_TOP; } diff --git a/src/client/views/global/globalCssVariables.scss.d.ts b/src/client/views/global/globalCssVariables.scss.d.ts index 537ea1e5d..efb702564 100644 --- a/src/client/views/global/globalCssVariables.scss.d.ts +++ b/src/client/views/global/globalCssVariables.scss.d.ts @@ -12,6 +12,9 @@ interface IGlobalScss { TREE_BULLET_WIDTH: string; INK_MASK_SIZE: number; MEDIUM_GRAY: string; + CAROUSEL3D_CENTER_SCALE: string; + CAROUSEL3D_SIDE_SCALE: string; + CAROUSEL3D_TOP: string; } declare const globalCssVariables: IGlobalScss; diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx index 3abe7a331..1cc09a63c 100644 --- a/src/client/views/nodes/ComparisonBox.tsx +++ b/src/client/views/nodes/ComparisonBox.tsx @@ -41,18 +41,17 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl this._disposers[disposerId]?.(); if (ele) { // create disposers identified by disposerId to remove drag & drop listeners - this._disposers[disposerId] = DragManager.MakeDropTarget(ele, (e, dropEvent) => this.dropHandler(e, dropEvent, fieldKey), this.layoutDoc); + this._disposers[disposerId] = DragManager.MakeDropTarget(ele, (e, dropEvent) => this.internalDrop(e, dropEvent, fieldKey), this.layoutDoc); } }; @undoBatch - private dropHandler = (event: Event, dropEvent: DragManager.DropEvent, fieldKey: string) => { + private internalDrop = (event: Event, dropEvent: DragManager.DropEvent, fieldKey: string) => { if (dropEvent.complete.docDragData) { event.stopPropagation(); // prevent parent Doc from registering new position so that it snaps back into place const droppedDocs = dropEvent.complete.docDragData?.droppedDocuments; - if (droppedDocs?.length) { - this.dataDoc[fieldKey] = droppedDocs[0]; - } + droppedDocs.lastElement().embedContainer = this.dataDoc; + this.dataDoc[fieldKey] = droppedDocs.lastElement(); } }; @@ -130,9 +129,6 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl return whichDoc ? ( <> <DocumentView - ref={r => { - //whichDoc !== targetDoc && r?.focus(whichDoc, { instant: true }); - }} {...this.props} NativeWidth={returnZero} NativeHeight={returnZero} diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index ab285b230..cc105326f 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -38,7 +38,6 @@ import { EditableView } from '../EditableView'; import { GestureOverlay } from '../GestureOverlay'; import { InkingStroke } from '../InkingStroke'; import { LightboxView } from '../LightboxView'; -import { OverlayView } from '../OverlayView'; import { StyleProp } from '../StyleProvider'; import { UndoStack } from '../UndoStack'; import { CollectionFreeFormDocumentView } from './CollectionFreeFormDocumentView'; @@ -117,6 +116,7 @@ export interface DocComponentView { brushView?: (view: { width: number; height: number; panX: number; panY: number }) => void; getView?: (doc: Doc) => Promise<Opt<DocumentView>>; // returns a nested DocumentView for the specified doc or undefined addDocTab?: (doc: Doc, where: OpenWhere) => boolean; // determines how to add a document - used in following links to open the target ina local lightbox + addDocument?: (doc: Doc | Doc[], annotationKey?: string) => boolean; // add a document (used only by collections) reverseNativeScaling?: () => boolean; // DocumentView's setup screenToLocal based on the doc having a nativeWidth/Height. However, some content views (e.g., FreeFormView w/ fitContentsToBox set) may ignore the native dimensions so this flags the DocumentView to not do Nativre scaling. shrinkWrap?: () => void; // requests a document to display all of its contents with no white space. currently only implemented (needed?) for freeform views select?: (ctrlKey: boolean, shiftKey: boolean) => void; diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index 128cfffb2..8dd322e05 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -9,7 +9,7 @@ import { LinkManager } from '../client/util/LinkManager'; import { scriptingGlobal, ScriptingGlobals } from '../client/util/ScriptingGlobals'; import { SelectionManager } from '../client/util/SelectionManager'; import { afterDocDeserialize, autoObject, Deserializable, SerializationHelper } from '../client/util/SerializationHelper'; -import { UndoManager } from '../client/util/UndoManager'; +import { undoable, UndoManager } from '../client/util/UndoManager'; import { decycle } from '../decycler/decycler'; import { DashColor, incrementTitleCopy, intersectRect, Utils } from '../Utils'; import { DateField } from './DateField'; @@ -211,14 +211,14 @@ export class Doc extends RefField { public static get MyTrails() { return DocCast(Doc.ActiveDashboard?.myTrails); } - public static IsInMyOverlay(doc:Doc) { + public static IsInMyOverlay(doc: Doc) { return DocListCast(Doc.MyOverlayDocs?.data).includes(doc); } - public static AddToMyOverlay(doc:Doc) { + public static AddToMyOverlay(doc: Doc) { Doc.AddDocToList(Doc.MyOverlayDocs, undefined, doc); } - public static RemFromMyOverlay(doc:Doc) { - Doc.RemoveDocFromList(Doc.MyOverlayDocs, undefined, doc) + public static RemFromMyOverlay(doc: Doc) { + Doc.RemoveDocFromList(Doc.MyOverlayDocs, undefined, doc); } public static get MyOverlayDocs() { return DocCast(Doc.UserDoc().myOverlayDocs); @@ -1520,6 +1520,24 @@ export namespace Doc { return style; } + export function Paste(docids: string[], clone: boolean, addDocument: (doc: Doc | Doc[]) => boolean, ptx?: number, pty?: number, newPoint?: number[]) { + DocServer.GetRefFields(docids).then(async fieldlist => { + const list = Array.from(Object.values(fieldlist)) + .map(d => DocCast(d)) + .filter(d => d); + const docs = clone ? (await Promise.all(Doc.MakeClones(list, false))).map(res => res.clone) : list; + if (ptx !== undefined && pty !== undefined && newPoint !== undefined) { + const firstx = list.length ? NumCast(list[0].x) + ptx - newPoint[0] : 0; + const firsty = list.length ? NumCast(list[0].y) + pty - newPoint[1] : 0; + docs.map(doc => { + doc.x = NumCast(doc.x) - firstx; + doc.y = NumCast(doc.y) - firsty; + }); + } + undoable(addDocument, 'Paste Doc')(docs); // embedContainer gets set in addDocument + }); + } + // prettier-ignore export function toIcon(doc?: Doc, isOpen?: boolean) { switch (StrCast(doc?.type)) { |