aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/Utils.ts2
-rw-r--r--src/client/documents/Documents.ts4
-rw-r--r--src/client/util/DragManager.ts9
-rw-r--r--src/client/views/DashboardView.tsx1
-rw-r--r--src/client/views/DocumentDecorations.tsx12
-rw-r--r--src/client/views/GlobalKeyHandler.ts46
-rw-r--r--src/client/views/PreviewCursor.tsx21
-rw-r--r--src/client/views/PropertiesButtons.tsx2
-rw-r--r--src/client/views/collections/CollectionCarousel3DView.scss14
-rw-r--r--src/client/views/collections/CollectionCarousel3DView.tsx32
-rw-r--r--src/client/views/global/globalCssVariables.scss7
-rw-r--r--src/client/views/global/globalCssVariables.scss.d.ts3
-rw-r--r--src/client/views/nodes/ComparisonBox.tsx12
-rw-r--r--src/client/views/nodes/DocumentView.tsx2
-rw-r--r--src/fields/Doc.ts28
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)) {