aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBob Zeleznik <zzzman@gmail.com>2020-05-09 21:43:04 -0400
committerBob Zeleznik <zzzman@gmail.com>2020-05-09 21:43:04 -0400
commit638fb6b16c4d69090e3806cca0a1a1909ec612c9 (patch)
tree421c6c76f93ef7f5743c011e936a411aab3298cd
parent5c876f2f456f75e9886946f738f07a730688f38a (diff)
added document clone and paste for all collections
-rw-r--r--src/client/views/DocumentDecorations.tsx4
-rw-r--r--src/client/views/GlobalKeyHandler.ts65
-rw-r--r--src/client/views/MainView.tsx2
-rw-r--r--src/client/views/PreviewCursor.tsx91
-rw-r--r--src/client/views/collections/CollectionTreeView.tsx6
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx12
-rw-r--r--src/client/views/collections/collectionFreeForm/MarqueeView.tsx5
7 files changed, 127 insertions, 58 deletions
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 9b6105811..1054822c7 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -174,8 +174,8 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
}
@undoBatch
@action
- onCloseClick = async (e: PointerEvent) => {
- if (e.button === 0) {
+ onCloseClick = async (e: PointerEvent | undefined) => {
+ if (!e?.button) {
const recent = Cast(Doc.UserDoc().myRecentlyClosed, Doc) as Doc;
const selected = SelectionManager.SelectedDocuments().slice();
SelectionManager.DeselectAll();
diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts
index d9281ac24..3fd14735b 100644
--- a/src/client/views/GlobalKeyHandler.ts
+++ b/src/client/views/GlobalKeyHandler.ts
@@ -1,10 +1,10 @@
-import { UndoManager } from "../util/UndoManager";
+import { UndoManager, undoBatch } from "../util/UndoManager";
import { SelectionManager } from "../util/SelectionManager";
import { CollectionDockingView } from "./collections/CollectionDockingView";
import { MainView } from "./MainView";
import { DragManager } from "../util/DragManager";
import { action, runInAction } from "mobx";
-import { Doc } from "../../new_fields/Doc";
+import { Doc, DocListCast } from "../../new_fields/Doc";
import { DictationManager } from "../util/DictationManager";
import SharingManager from "../util/SharingManager";
import { Cast, PromiseValue, NumCast } from "../../new_fields/Types";
@@ -16,6 +16,11 @@ import GoogleAuthenticationManager from "../apis/GoogleAuthenticationManager";
import { CollectionFreeFormView } from "./collections/collectionFreeForm/CollectionFreeFormView";
import { MarqueeView } from "./collections/collectionFreeForm/MarqueeView";
import { Id } from "../../new_fields/FieldSymbols";
+import { DocumentDecorations } from "./DocumentDecorations";
+import { DocumentType } from "../documents/DocumentTypes";
+import { DocServer } from "../DocServer";
+import { List } from "../../new_fields/List";
+import { DateField } from "../../new_fields/DateField";
const modifiers = ["control", "meta", "shift", "alt"];
type KeyHandler = (keycode: string, e: KeyboardEvent) => KeyControlInfo | Promise<KeyControlInfo>;
@@ -245,15 +250,25 @@ export default class KeyManager {
preventDefault = false;
break;
case "x":
+ if (SelectionManager.SelectedDocuments().length) {
+ const bds = DocumentDecorations.Instance.Bounds;
+ const pt = [bds.x + (bds.r - bds.x) / 2, bds.y + (bds.b - bds.y) / 2];
+ const text = `__DashDocId(${pt[0]},${pt[1]}):` + SelectionManager.SelectedDocuments().map(dv => dv.Document[Id]).join(":");
+ SelectionManager.SelectedDocuments().length && navigator.clipboard.writeText(text);
+ DocumentDecorations.Instance.onCloseClick(undefined);
+ stopPropagation = false;
+ preventDefault = false;
+ }
+ break;
case "c":
- SelectionManager.SelectedDocuments().length && navigator.clipboard.writeText("__DashDocId:" + SelectionManager.SelectedDocuments()[0].Document[Id]);
- // window.getSelection()?.removeAllRanges();
- // let range = document.createRange();
- // range.selectNode(SelectionManager.SelectedDocuments()[0].ContentDiv!);
- // window.getSelection()?.addRange(range);
- // document.execCommand('copy');
- stopPropagation = false;
- preventDefault = false;
+ if (SelectionManager.SelectedDocuments().length) {
+ const bds = DocumentDecorations.Instance.Bounds;
+ const pt = [bds.x + (bds.r - bds.x) / 2, bds.y + (bds.b - bds.y) / 2];
+ const text = `__DashDocId(${pt[0]},${pt[1]}):` + SelectionManager.SelectedDocuments().map(dv => dv.Document[Id]).join(":");
+ SelectionManager.SelectedDocuments().length && navigator.clipboard.writeText(text);;
+ stopPropagation = false;
+ preventDefault = false;
+ }
break;
}
@@ -263,6 +278,36 @@ export default class KeyManager {
};
});
+ public paste(e: ClipboardEvent) {
+ if (e.clipboardData?.getData("text/plain") !== "" && e.clipboardData?.getData("text/plain").startsWith("__DashDocId(")) {
+ const first = SelectionManager.SelectedDocuments().length ? SelectionManager.SelectedDocuments()[0] : undefined;
+ if (first?.props.Document.type === DocumentType.COL) {
+ const docids = e.clipboardData.getData("text/plain").split(":");
+ let count = 1;
+ const list: Doc[] = [];
+ const targetDataDoc = Doc.GetProto(first.props.Document);
+ const fieldKey = Doc.LayoutFieldKey(first.props.Document);
+ const docList = DocListCast(targetDataDoc[fieldKey]);
+ docids.map((did, i) => i && DocServer.GetRefField(did).then(doc => {
+ count++;
+ if (doc instanceof Doc) {
+ list.push(doc);
+ }
+ if (count === docids.length) {
+ const added = list.filter(d => !docList.includes(d));
+ if (added.length) {
+ added.map(doc => doc.context = targetDataDoc);
+ undoBatch(() => {
+ targetDataDoc[fieldKey] = new List<Doc>([...docList, ...added]);
+ targetDataDoc[fieldKey + "-lastModified"] = new DateField(new Date(Date.now()));
+ })();
+ }
+ }
+ }));
+ }
+ }
+ }
+
async printClipboard() {
const text: string = await navigator.clipboard.readText();
}
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index b6dfe60e5..cbaae63bc 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -83,12 +83,14 @@ export class MainView extends React.Component {
firstScriptTag.parentNode!.insertBefore(tag, firstScriptTag);
window.removeEventListener("keydown", KeyManager.Instance.handle);
window.addEventListener("keydown", KeyManager.Instance.handle);
+ window.addEventListener("paste", KeyManager.Instance.paste);
}
componentWillUnMount() {
window.removeEventListener("keydown", KeyManager.Instance.handle);
window.removeEventListener("pointerdown", this.globalPointerDown);
window.removeEventListener("pointerup", this.globalPointerUp);
+ window.removeEventListener("paste", KeyManager.Instance.paste);
}
constructor(props: Readonly<{}>) {
diff --git a/src/client/views/PreviewCursor.tsx b/src/client/views/PreviewCursor.tsx
index b9036bf1e..14b5b3fce 100644
--- a/src/client/views/PreviewCursor.tsx
+++ b/src/client/views/PreviewCursor.tsx
@@ -7,13 +7,15 @@ import { Docs } from '../documents/Documents';
import { Doc } from '../../new_fields/Doc';
import { Transform } from "../util/Transform";
import { DocServer } from '../DocServer';
+import { NumCast } from '../../new_fields/Types';
+import { undoBatch } from '../util/UndoManager';
@observer
export class PreviewCursor extends React.Component<{}> {
static _onKeyPress?: (e: KeyboardEvent) => void;
static _getTransform: () => Transform;
+ static _addDocument: (doc: Doc | Doc[]) => void;
static _addLiveTextDoc: (doc: Doc) => void;
- static _addDocument: (doc: Doc) => boolean;
static _nudge: (x: number, y: number) => boolean;
@observable static _clickPoint = [0, 0];
@observable public static Visible = false;
@@ -28,62 +30,73 @@ export class PreviewCursor extends React.Component<{}> {
const newPoint = PreviewCursor._getTransform().transformPoint(PreviewCursor._clickPoint[0], PreviewCursor._clickPoint[1]);
runInAction(() => PreviewCursor.Visible = false);
+ // tests for URL and makes web document
+ const re: any = /^https?:\/\//g;
if (e.clipboardData.getData("text/plain") !== "") {
// tests for youtube and makes video document
if (e.clipboardData.getData("text/plain").indexOf("www.youtube.com/watch") !== -1) {
const url = e.clipboardData.getData("text/plain").replace("youtube.com/watch?v=", "youtube.com/embed/");
- return PreviewCursor._addDocument(Docs.Create.VideoDocument(url, {
+ undoBatch(() => PreviewCursor._addDocument(Docs.Create.VideoDocument(url, {
title: url, _width: 400, _height: 315,
_nativeWidth: 600, _nativeHeight: 472.5,
x: newPoint[0], y: newPoint[1]
- }));
+ })))();
}
- // tests for URL and makes web document
- const re: any = /^https?:\/\//g;
- if (re.test(e.clipboardData.getData("text/plain"))) {
+ else if (re.test(e.clipboardData.getData("text/plain"))) {
const url = e.clipboardData.getData("text/plain");
- return PreviewCursor._addDocument(Docs.Create.WebDocument(url, {
+ undoBatch(() => PreviewCursor._addDocument(Docs.Create.WebDocument(url, {
title: url, _width: 500, _height: 300,
// nativeWidth: 300, nativeHeight: 472.5,
x: newPoint[0], y: newPoint[1]
- }));
+ })))();
}
- if (e.clipboardData.getData("text/plain").includes("__DashDocId:")) {
- const docid = e.clipboardData.getData("text/plain").split("__DashDocId:")[1];
- return DocServer.GetRefField(docid).then(doc => {
+ else if (e.clipboardData.getData("text/plain").startsWith("__DashDocId(")) {
+ const docids = e.clipboardData.getData("text/plain").split(":");
+ const strs = docids[0].split(",");
+ const ptx = Number(strs[0].substring("__DashDocId(".length));
+ const pty = Number(strs[1].substring(0, strs[1].length - 1));
+ const center = PreviewCursor._getTransform().transformPoint(ptx, pty);
+ let count = 1;
+ const list: Doc[] = [];
+ docids.map((did, i) => i && DocServer.GetRefField(did).then(doc => {
+ count++;
if (doc instanceof Doc) {
- const alias = Doc.MakeAlias(doc);
- alias.x = newPoint[0];
- alias.y = newPoint[1];
- PreviewCursor._addDocument(alias);
+ const alias = Doc.MakeClone(doc);
+ alias.x = newPoint[0] + NumCast(doc.x) - center[0];
+ alias.y = newPoint[1] + NumCast(doc.y) - center[1];
+ list.push(alias);
}
- });
- }
+ if (count === docids.length) {
+ undoBatch(() => PreviewCursor._addDocument(list))();
+ }
+ }));
- // creates text document
- return PreviewCursor._addLiveTextDoc(Docs.Create.TextDocument("", {
- _width: 500,
- limitHeight: 400,
- _autoHeight: true,
- x: newPoint[0],
- y: newPoint[1],
- title: "-pasted text-"
- }));
- }
- //pasting in images
- if (e.clipboardData.getData("text/html") !== "" && e.clipboardData.getData("text/html").includes("<img src=")) {
- const re: any = /<img src="(.*?)"/g;
- const arr: any[] = re.exec(e.clipboardData.getData("text/html"));
+ } else {
+ // creates text document
+ undoBatch(() => PreviewCursor._addLiveTextDoc(Docs.Create.TextDocument("", {
+ _width: 500,
+ limitHeight: 400,
+ _autoHeight: true,
+ x: newPoint[0],
+ y: newPoint[1],
+ title: "-pasted text-"
+ })))();
+ }
+ } else
+ //pasting in images
+ if (e.clipboardData.getData("text/html") !== "" && e.clipboardData.getData("text/html").includes("<img src=")) {
+ const re: any = /<img src="(.*?)"/g;
+ const arr: any[] = re.exec(e.clipboardData.getData("text/html"));
- return PreviewCursor._addDocument(Docs.Create.ImageDocument(
- arr[1], {
- _width: 300, title: arr[1],
- x: newPoint[0],
- y: newPoint[1],
- }));
- }
+ undoBatch(() => PreviewCursor._addDocument(Docs.Create.ImageDocument(
+ arr[1], {
+ _width: 300, title: arr[1],
+ x: newPoint[0],
+ y: newPoint[1],
+ })))();
+ }
}
}
@@ -125,7 +138,7 @@ export class PreviewCursor extends React.Component<{}> {
onKeyPress: (e: KeyboardEvent) => void,
addLiveText: (doc: Doc) => void,
getTransform: () => Transform,
- addDocument: (doc: Doc) => boolean,
+ addDocument: (doc: Doc | Doc[]) => boolean,
nudge: (nudgeX: number, nudgeY: number) => boolean) {
this._clickPoint = [x, y];
this._onKeyPress = onKeyPress;
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index f6fcc1ac4..8cd34e7ed 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -396,7 +396,7 @@ class TreeView extends React.Component<TreeViewProps> {
}
showContextMenu = (e: React.MouseEvent) => {
- simulateMouseClick(this._docRef.current!.ContentDiv!, e.clientX, e.clientY + 30, e.screenX, e.screenY + 30);
+ this._docRef.current?.ContentDiv && simulateMouseClick(this._docRef.current.ContentDiv, e.clientX, e.clientY + 30, e.screenX, e.screenY + 30);
e.stopPropagation();
}
focusOnDoc = (doc: Doc) => DocumentManager.Instance.getFirstDocumentView(doc)?.props.focus(doc, true);
@@ -772,6 +772,9 @@ export class CollectionTreeView extends CollectionSubView<Document, Partial<coll
</div >;
}
+ onKeyPress = (e: React.KeyboardEvent) => {
+ console.log(e);
+ }
render() {
if (!(this.props.Document instanceof Doc)) return (null);
const dropAction = StrCast(this.props.Document.childDropAction) as dropActionType;
@@ -786,6 +789,7 @@ export class CollectionTreeView extends CollectionSubView<Document, Partial<coll
paddingRight: `${NumCast(this.props.Document._xPadding, 10)}px`,
paddingTop: `${NumCast(this.props.Document._yPadding, 20)}px`
}}
+ onKeyPress={this.onKeyPress}
onContextMenu={this.onContextMenu}
onWheel={(e: React.WheelEvent) => this._mainEle && this._mainEle.scrollHeight > this._mainEle.clientHeight && e.stopPropagation()}
onDrop={this.onTreeDrop}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 6cc0cfcd2..1bc59c727 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1246,8 +1246,16 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
return false;
});
@computed get marqueeView() {
- return <MarqueeView {...this.props} nudge={this.nudge} activeDocuments={this.getActiveDocuments} selectDocuments={this.selectDocuments} addDocument={this.addDocument}
- addLiveTextDocument={this.addLiveTextBox} getContainerTransform={this.getContainerTransform} getTransform={this.getTransform} isAnnotationOverlay={this.isAnnotationOverlay}>
+ return <MarqueeView {...this.props}
+ nudge={this.nudge}
+ addDocTab={this.addDocTab}
+ activeDocuments={this.getActiveDocuments}
+ selectDocuments={this.selectDocuments}
+ addDocument={this.addDocument}
+ addLiveTextDocument={this.addLiveTextBox}
+ getContainerTransform={this.getContainerTransform}
+ getTransform={this.getTransform}
+ isAnnotationOverlay={this.isAnnotationOverlay}>
<CollectionFreeFormViewPannableContents centeringShiftX={this.centeringShiftX} centeringShiftY={this.centeringShiftY} shifted={!this.nativeHeight && !this.isAnnotationOverlay}
easing={this.easing} viewDefDivClick={this.props.viewDefDivClick} zoomScaling={this.zoomScaling} panX={this.panX} panY={this.panY}>
{this.children}
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 1addea6a1..35d925bca 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -24,13 +24,10 @@ import React = require("react");
interface MarqueeViewProps {
getContainerTransform: () => Transform;
getTransform: () => Transform;
- addDocument: (doc: Doc) => boolean;
activeDocuments: () => Doc[];
selectDocuments: (docs: Doc[], ink: { Document: Doc, Ink: Map<any, any> }[]) => void;
- removeDocument: (doc: Doc) => boolean;
addLiveTextDocument: (doc: Doc) => void;
isSelected: () => boolean;
- isAnnotationOverlay?: boolean;
nudge: (x: number, y: number) => boolean;
setPreviewCursor?: (func: (x: number, y: number, drag: boolean) => void) => void;
}
@@ -248,7 +245,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
} else {
this._downX = x;
this._downY = y;
- PreviewCursor.Show(x, y, this.onKeyPress, this.props.addLiveTextDocument, this.props.getTransform, this.props.addDocument, this.props.nudge);
+ PreviewCursor.Show(x, y, this.onKeyPress, this.props.addLiveTextDocument, this.props.getTransform, this.props.addDocument, this.props.addDocTab, this.props.nudge);
}
});