From c1f49a0974982b803c565b6ac3c8931be7c8972f Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Fri, 8 May 2020 16:57:30 -0400
Subject: added " " for switching between pan/zoom & marquee.

---
 src/client/views/PreviewCursor.tsx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'src/client/views/PreviewCursor.tsx')

diff --git a/src/client/views/PreviewCursor.tsx b/src/client/views/PreviewCursor.tsx
index df30c1215..80c7f3d25 100644
--- a/src/client/views/PreviewCursor.tsx
+++ b/src/client/views/PreviewCursor.tsx
@@ -81,7 +81,7 @@ export class PreviewCursor extends React.Component<{}> {
         if (e.key !== "Escape" && e.key !== "Backspace" && e.key !== "Delete" && e.key !== "CapsLock" &&
             e.key !== "Alt" && e.key !== "Shift" && e.key !== "Meta" && e.key !== "Control" &&
             e.key !== "Insert" && e.key !== "Home" && e.key !== "End" && e.key !== "PageUp" && e.key !== "PageDown" &&
-            e.key !== "NumLock" &&
+            e.key !== "NumLock" && e.key !== " " &&
             (e.keyCode < 112 || e.keyCode > 123) && // F1 thru F12 keys
             !e.key.startsWith("Arrow") &&
             !e.defaultPrevented) {
-- 
cgit v1.2.3-70-g09d2


From 4914965affb984e04e847460ce1b5750807b316f Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Sat, 9 May 2020 15:56:11 -0400
Subject: fixed missing gear in golden layout.  fixed double dragging events. 
 changed dragging to give prefernce to modifier keys over dropactions. 
 changed names of Documents to Catalog.   added document copy past with ctrl
 c/ctrl v

---
 src/client/util/DragManager.ts                         |  7 ++-----
 src/client/views/GlobalKeyHandler.ts                   | 10 ++++++++++
 src/client/views/MainView.tsx                          |  3 +--
 src/client/views/PreviewCursor.tsx                     | 13 +++++++++++++
 src/client/views/collections/CollectionDockingView.tsx |  2 +-
 src/client/views/collections/CollectionSubView.tsx     | 10 ++++++----
 src/client/views/collections/CollectionTreeView.tsx    |  3 +--
 src/client/views/collections/CollectionView.tsx        | 10 +++++-----
 src/client/views/nodes/DocumentView.tsx                | 15 ++++++++++-----
 src/server/authentication/models/current_user_utils.ts | 14 +++++++-------
 10 files changed, 56 insertions(+), 31 deletions(-)

(limited to 'src/client/views/PreviewCursor.tsx')

diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index cc8cc38dd..4f547e2f7 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -176,7 +176,7 @@ export namespace DragManager {
         element: HTMLElement,
         dropFunc: (e: Event, de: DropEvent) => void,
         doc?: Doc,
-        preDropFunc?: (e: Event, de: DropEvent) => void,
+        preDropFunc?: (e: Event, de: DropEvent, targetAction: dropActionType) => void,
     ): DragDropDisposer {
         if ("canDrop" in element.dataset) {
             throw new Error(
@@ -187,10 +187,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;
-            if (de.complete.docDragData && doc?.targetDropAction) {
-                de.complete.docDragData.dropAction = StrCast(doc.targetDropAction) as dropActionType;
-            }
-            preDropFunc?.(e, de);
+            preDropFunc?.(e, de, StrCast(doc?.targetDropAction) as dropActionType);
         };
         element.addEventListener("dashOnDrop", handler);
         doc && element.addEventListener("dashPreDrop", preDropHandler);
diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts
index c73e1a66a..d9281ac24 100644
--- a/src/client/views/GlobalKeyHandler.ts
+++ b/src/client/views/GlobalKeyHandler.ts
@@ -15,6 +15,7 @@ import { DocumentView } from "./nodes/DocumentView";
 import GoogleAuthenticationManager from "../apis/GoogleAuthenticationManager";
 import { CollectionFreeFormView } from "./collections/collectionFreeForm/CollectionFreeFormView";
 import { MarqueeView } from "./collections/collectionFreeForm/MarqueeView";
+import { Id } from "../../new_fields/FieldSymbols";
 
 const modifiers = ["control", "meta", "shift", "alt"];
 type KeyHandler = (keycode: string, e: KeyboardEvent) => KeyControlInfo | Promise<KeyControlInfo>;
@@ -240,8 +241,17 @@ export default class KeyManager {
                 break;
             case "a":
             case "v":
+                stopPropagation = false;
+                preventDefault = false;
+                break;
             case "x":
             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;
                 break;
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index fad6bf295..b6dfe60e5 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -249,8 +249,7 @@ export class MainView extends React.Component {
             title: "Collection " + workspaceCount,
         };
         const freeformDoc = CurrentUserUtils.GuestTarget || Docs.Create.FreeformDocument([], freeformOptions);
-        Doc.AddDocToList(Doc.GetProto(Doc.UserDoc().myDocuments as Doc), "data", freeformDoc);
-        const mainDoc = Docs.Create.StandardCollectionDockingDocument([{ doc: freeformDoc, initialWidth: 600, path: [Doc.UserDoc().myDocuments as Doc] }], { title: `Workspace ${workspaceCount}` }, id, "row");
+        const mainDoc = Docs.Create.StandardCollectionDockingDocument([{ doc: freeformDoc, initialWidth: 600, path: [Doc.UserDoc().myCatalog as Doc] }], { title: `Workspace ${workspaceCount}` }, id, "row");
 
         const toggleTheme = ScriptField.MakeScript(`self.darkScheme = !self.darkScheme`);
         mainDoc.contextMenuScripts = new List<ScriptField>([toggleTheme!]);
diff --git a/src/client/views/PreviewCursor.tsx b/src/client/views/PreviewCursor.tsx
index 80c7f3d25..b9036bf1e 100644
--- a/src/client/views/PreviewCursor.tsx
+++ b/src/client/views/PreviewCursor.tsx
@@ -6,6 +6,7 @@ import "./PreviewCursor.scss";
 import { Docs } from '../documents/Documents';
 import { Doc } from '../../new_fields/Doc';
 import { Transform } from "../util/Transform";
+import { DocServer } from '../DocServer';
 
 @observer
 export class PreviewCursor extends React.Component<{}> {
@@ -49,6 +50,18 @@ export class PreviewCursor extends React.Component<{}> {
                     }));
                 }
 
+                if (e.clipboardData.getData("text/plain").includes("__DashDocId:")) {
+                    const docid = e.clipboardData.getData("text/plain").split("__DashDocId:")[1];
+                    return DocServer.GetRefField(docid).then(doc => {
+                        if (doc instanceof Doc) {
+                            const alias = Doc.MakeAlias(doc);
+                            alias.x = newPoint[0];
+                            alias.y = newPoint[1];
+                            PreviewCursor._addDocument(alias);
+                        }
+                    });
+                }
+
                 // creates text document
                 return PreviewCursor._addLiveTextDoc(Docs.Create.TextDocument("", {
                     _width: 500,
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index c1edc0fe7..6fdb96f0d 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -527,7 +527,7 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
                                 gearSpan);
                             tab.buttonDisposer?.();
                         }
-                    });
+                    }, { fireImmediately: true });
 
                 tab.reactComponents = [gearSpan];
                 tab.element.append(gearSpan);
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index d1c2d9a76..4fef16315 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -16,7 +16,7 @@ import { DocServer } from "../../DocServer";
 import { Docs, DocumentOptions } from "../../documents/Documents";
 import { DocumentType } from "../../documents/DocumentTypes";
 import { Networking } from "../../Network";
-import { DragManager } from "../../util/DragManager";
+import { DragManager, dropActionType } from "../../util/DragManager";
 import { ImageUtils } from "../../util/Import & Export/ImageUtils";
 import { InteractionUtils } from "../../util/InteractionUtils";
 import { undoBatch, UndoManager } from "../../util/UndoManager";
@@ -195,10 +195,12 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
         protected onGesture(e: Event, ge: GestureUtils.GestureEvent) {
         }
 
-        protected onInternalPreDrop(e: Event, de: DragManager.DropEvent) {
+        protected onInternalPreDrop(e: Event, de: DragManager.DropEvent, targetAction: dropActionType) {
             if (de.complete.docDragData) {
-                if (de.complete.docDragData.draggedDocuments.some(d => this.childDocs.includes(d))) {
-                    de.complete.docDragData.dropAction = "move";
+                // if targetDropAction is, say 'alias', but we're just dragging within a collection, we want to ignore the targetAction.
+                // otherwise, the targetAction should become the actual action (which can still be overridden by the userDropAction -eg, shift/ctrl keys)
+                if (targetAction && !de.complete.docDragData.draggedDocuments.some(d => d.context === this.props.Document && this.childDocs.includes(d))) {
+                    de.complete.docDragData.dropAction = targetAction;
                 }
                 e.stopPropagation();
             }
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 58d021b5c..7086ba380 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -410,7 +410,6 @@ class TreeView extends React.Component<TreeViewProps> {
     @computed
     get renderTitle() {
         TraceMobx();
-        const onItemDown = SetupDrag(this._tref, () => this.dataDoc, this.move, this.props.dropAction, this.props.treeViewId[Id], true);
         (!TreeView._editTitleScript) && (TreeView._editTitleScript = ScriptField.MakeFunction("setInPlace(self, 'editTitle', true)"));
         const headerElements = (
             <>
@@ -432,7 +431,7 @@ class TreeView extends React.Component<TreeViewProps> {
             <FontAwesomeIcon title="open in pane on right" icon="angle-right" size="lg" />
         </div>);
         return <>
-            <div className="docContainer" ref={this._tref} title="click to edit title" id={`docContainer-${this.props.parentKey}`} onPointerDown={onItemDown}
+            <div className="docContainer" ref={this._tref} title="click to edit title" id={`docContainer-${this.props.parentKey}`}
                 style={{
                     fontWeight: this.props.document.searchMatch ? "bold" : undefined,
                     textDecoration: Doc.GetT(this.props.document, "title", "string", true) ? "underline" : undefined,
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index b96f8150d..6c96baede 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -69,15 +69,15 @@ export enum CollectionViewType {
     Pile = "pileup"
 }
 export interface CollectionViewCustomProps {
-    filterAddDocument: (doc: Doc) => boolean;  // allows a document that renders a Collection view to filter or modify any documents added to the collection (see PresBox for an example)
+    filterAddDocument: (doc: Doc | Doc[]) => boolean;  // allows a document that renders a Collection view to filter or modify any documents added to the collection (see PresBox for an example)
     childLayoutTemplate?: () => Opt<Doc>;  // specify a layout Doc template to use for children of the collection
     childLayoutString?: string;  // specify a layout string to use for children of the collection
 }
 
 export interface CollectionRenderProps {
-    addDocument: (document: Doc) => boolean;
-    removeDocument: (document: Doc) => boolean;
-    moveDocument: (document: Doc, targetCollection: Doc | undefined, addDocument: (document: Doc) => boolean) => boolean;
+    addDocument: (document: Doc | Doc[]) => boolean;
+    removeDocument: (document: Doc | Doc[]) => boolean;
+    moveDocument: (document: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[]) => boolean) => boolean;
     active: () => boolean;
     whenActiveChanged: (isActive: boolean) => void;
     PanelWidth: () => number;
@@ -152,7 +152,7 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
     // otherwise, the document being moved must be able to be removed from its container before
     // moving it into the target.  
     @action.bound
-    moveDocument = (doc: Doc, targetCollection: Doc | undefined, addDocument: (doc: Doc) => boolean): boolean => {
+    moveDocument = (doc: Doc, targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[]) => boolean): boolean => {
         if (Doc.AreProtosEqual(this.props.Document, targetCollection)) {
             return true;
         }
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index e3b69b8f3..ebfc38a54 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -4,7 +4,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { action, computed, observable, runInAction } from "mobx";
 import { observer } from "mobx-react";
 import * as rp from "request-promise";
-import { Doc, DocListCast, HeightSym, Opt, WidthSym } from "../../../new_fields/Doc";
+import { Doc, DocListCast, HeightSym, Opt, WidthSym, DataSym } from "../../../new_fields/Doc";
 import { Document } from '../../../new_fields/documentSchemas';
 import { Id } from '../../../new_fields/FieldSymbols';
 import { InkTool } from '../../../new_fields/InkField';
@@ -15,7 +15,7 @@ import { BoolCast, Cast, NumCast, StrCast } from "../../../new_fields/Types";
 import { ImageField } from '../../../new_fields/URLField';
 import { TraceMobx } from '../../../new_fields/util';
 import { GestureUtils } from '../../../pen-gestures/GestureUtils';
-import { emptyFunction, OmitKeys, returnOne, returnTransparent, Utils } from "../../../Utils";
+import { emptyFunction, OmitKeys, returnOne, returnTransparent, Utils, emptyPath } from "../../../Utils";
 import { GooglePhotos } from '../../apis/google_docs/GooglePhotosClientUtils';
 import { ClientRecommender } from '../../ClientRecommender';
 import { DocServer } from "../../DocServer";
@@ -549,7 +549,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                 if (!e.altKey && (!this.topMost || this.Document.onDragStart || this.onClickHandler) && (e.buttons === 1 || InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE))) {
                     document.removeEventListener("pointermove", this.onPointerMove);
                     document.removeEventListener("pointerup", this.onPointerUp);
-                    this.startDragging(this._downX, this._downY, this.props.dropAction ? this.props.dropAction : this.Document.dropAction ? this.Document.dropAction as any : e.ctrlKey || e.altKey ? "alias" : undefined);
+                    this.startDragging(this._downX, this._downY, ((e.ctrlKey || e.altKey) && "alias") || (this.props.dropAction || this.Document.dropAction || undefined) as dropActionType);
                 }
             }
             e.stopPropagation(); // doesn't actually stop propagation since all our listeners are listening to events on 'document'  however it does mark the event as cancelBubble=true which we test for in the move event handlers
@@ -721,6 +721,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
 
         let open = cm.findByDescription("Add a Perspective...");
         const openItems: ContextMenuProps[] = open && "subitems" in open ? open.subitems : [];
+        openItems.push({ description: "New Echo        ", event: () => this.props.addDocTab(Doc.MakeAlias(this.props.Document), "onRight"), icon: "layer-group" });
         openItems.push({ description: "Open Fields     ", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { _width: 300, _height: 300 }), "onRight"), icon: "layer-group" });
         templateDoc && openItems.push({ description: "Open Template   ", event: () => this.props.addDocTab(templateDoc, "onRight"), icon: "eye" });
         if (!open) {
@@ -864,8 +865,12 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         const path = this.props.LibraryPath.reduce((p: string, d: Doc) => p + "/" + (Doc.AreProtosEqual(d, (Doc.UserDoc()["tabs-button-library"] as Doc).sourcePanel as Doc) ? "" : d.title), "");
         cm.addItem({
             description: `path: ${path}`, event: () => {
-                this.props.LibraryPath.map(lp => Doc.GetProto(lp).treeViewOpen = lp.treeViewOpen = true);
-                Doc.linkFollowHighlight(this.props.Document);
+                if (this.props.LibraryPath !== emptyPath) {
+                    this.props.LibraryPath.map(lp => Doc.GetProto(lp).treeViewOpen = lp.treeViewOpen = true);
+                    Doc.linkFollowHighlight(this.props.Document);
+                } else {
+                    Doc.AddDocToList(Doc.GetProto(Doc.UserDoc().myCatalog as Doc), "data", this.props.Document[DataSym]);
+                }
             }, icon: "check"
         });
     }
diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts
index a776b6f10..bebf77a8c 100644
--- a/src/server/authentication/models/current_user_utils.ts
+++ b/src/server/authentication/models/current_user_utils.ts
@@ -507,13 +507,13 @@ export class CurrentUserUtils {
 
         return doc.myWorkspaces as Doc;
     }
-    static setupDocumentCollection(doc: Doc) {
-        if (doc.myDocuments === undefined) {
-            doc.myDocuments = new PrefetchProxy(Docs.Create.TreeDocument([], {
-                title: "DOCUMENTS", _height: 42, forceActive: true, boxShadow: "0 0", treeViewPreventOpen: false, lockedPosition: true,
+    static setupCatalog(doc: Doc) {
+        if (doc.myCatalog === undefined) {
+            doc.myCatalog = new PrefetchProxy(Docs.Create.TreeDocument([], {
+                title: "CATALOG", _height: 42, forceActive: true, boxShadow: "0 0", treeViewPreventOpen: false, lockedPosition: true,
             }));
         }
-        return doc.myDocuments as Doc;
+        return doc.myCatalog as Doc;
     }
     static setupRecentlyClosed(doc: Doc) {
         // setup Recently Closed library item
@@ -533,7 +533,7 @@ export class CurrentUserUtils {
     // setup the Library button which will display the library panel.  This panel includes a collection of workspaces, documents, and recently closed views
     static setupLibraryPanel(doc: Doc, sidebarContainer: Doc) {
         const workspaces = CurrentUserUtils.setupWorkspaces(doc);
-        const documents = CurrentUserUtils.setupDocumentCollection(doc);
+        const documents = CurrentUserUtils.setupCatalog(doc);
         const recentlyClosed = CurrentUserUtils.setupRecentlyClosed(doc);
 
         if (doc["tabs-button-library"] === undefined) {
@@ -541,7 +541,7 @@ export class CurrentUserUtils {
                 _width: 50, _height: 25, title: "Library", _fontSize: 10,
                 letterSpacing: "0px", textTransform: "unset", borderRounding: "5px 5px 0px 0px", boxShadow: "3px 3px 0px rgb(34, 34, 34)",
                 sourcePanel: new PrefetchProxy(Docs.Create.TreeDocument([workspaces, documents, recentlyClosed, doc], {
-                    title: "Library", _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, childDropAction: "move", lockedPosition: true, boxShadow: "0 0", dontRegisterChildViews: true
+                    title: "Library", _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, childDropAction: "alias", lockedPosition: true, boxShadow: "0 0", dontRegisterChildViews: true
                 })) as any as Doc,
                 targetContainer: new PrefetchProxy(sidebarContainer) as any as Doc,
                 onClick: ScriptField.MakeScript("this.targetContainer.proto = this.sourcePanel;")
-- 
cgit v1.2.3-70-g09d2


From 638fb6b16c4d69090e3806cca0a1a1909ec612c9 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Sat, 9 May 2020 21:43:04 -0400
Subject: added document clone and paste for all collections

---
 src/client/views/DocumentDecorations.tsx           |  4 +-
 src/client/views/GlobalKeyHandler.ts               | 65 +++++++++++++---
 src/client/views/MainView.tsx                      |  2 +
 src/client/views/PreviewCursor.tsx                 | 91 ++++++++++++----------
 .../views/collections/CollectionTreeView.tsx       |  6 +-
 .../collectionFreeForm/CollectionFreeFormView.tsx  | 12 ++-
 .../collections/collectionFreeForm/MarqueeView.tsx |  5 +-
 7 files changed, 127 insertions(+), 58 deletions(-)

(limited to 'src/client/views/PreviewCursor.tsx')

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);
         }
     });
 
-- 
cgit v1.2.3-70-g09d2


From a3839d4b5a2180e2e80fa79f6eb4459e2976f380 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Mon, 11 May 2020 14:59:54 -0400
Subject: changed Cors behavior for WebBox(On for everything except
 GoogldDocs).  Update Freeze to work for ctrl-resizing text, and showing full
 screen.  reorged context menus.

---
 src/client/views/DocumentButtonBar.tsx             |  2 +-
 src/client/views/DocumentDecorations.scss          |  1 +
 src/client/views/DocumentDecorations.tsx           |  1 +
 src/client/views/MainView.tsx                      |  1 +
 src/client/views/PreviewCursor.tsx                 |  2 +-
 .../views/collections/CollectionDockingView.tsx    | 12 ++++----
 .../views/collections/CollectionStackingView.tsx   |  1 +
 .../collectionFreeForm/CollectionFreeFormView.tsx  | 27 +++++++++---------
 src/client/views/nodes/DocumentView.tsx            | 25 ++++++----------
 src/client/views/nodes/ImageBox.tsx                | 33 +++++++++++++---------
 src/client/views/nodes/WebBox.tsx                  |  8 ++----
 .../views/nodes/formattedText/FormattedTextBox.tsx | 18 +++++++++++-
 .../formattedText/FormattedTextBoxComment.tsx      |  2 +-
 src/new_fields/Doc.ts                              | 26 +++++++++++------
 .../authentication/models/current_user_utils.ts    |  2 +-
 15 files changed, 94 insertions(+), 67 deletions(-)

(limited to 'src/client/views/PreviewCursor.tsx')

diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx
index 48685302a..10d9ec401 100644
--- a/src/client/views/DocumentButtonBar.tsx
+++ b/src/client/views/DocumentButtonBar.tsx
@@ -194,7 +194,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
                     e.preventDefault();
                     let googleDoc = await Cast(dataDoc.googleDoc, Doc);
                     if (!googleDoc) {
-                        const options = { _width: 600, _nativeWidth: 960, _nativeHeight: 800, isAnnotating: false };
+                        const options = { _width: 600, _nativeWidth: 960, _nativeHeight: 800, isAnnotating: false, UseCors: false };
                         googleDoc = Docs.Create.WebDocument(googleDocUrl, options);
                         dataDoc.googleDoc = googleDoc;
                     }
diff --git a/src/client/views/DocumentDecorations.scss b/src/client/views/DocumentDecorations.scss
index 4f34eb9e3..15eb537da 100644
--- a/src/client/views/DocumentDecorations.scss
+++ b/src/client/views/DocumentDecorations.scss
@@ -72,6 +72,7 @@ $linkGap : 3px;
         grid-column-start: 5;
         grid-column-end: 7;
         border-radius: 100%;
+        background: dimgray;
 
         .borderRadiusTooltip {
             width: 10px;
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 1054822c7..9669c21a9 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -301,6 +301,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
         }
 
         SelectionManager.SelectedDocuments().forEach(action((element: DocumentView) => {
+            if (e.ctrlKey && !element.props.Document._nativeHeight) element.toggleNativeDimensions();
             if (dX !== 0 || dY !== 0 || dW !== 0 || dH !== 0) {
                 const doc = Document(element.rootDoc);
                 let nwidth = doc._nativeWidth || 0;
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index cbaae63bc..560dd5d11 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -249,6 +249,7 @@ export class MainView extends React.Component {
             _width: this._panelWidth * .7,
             _height: this._panelHeight,
             title: "Collection " + workspaceCount,
+            _LODdisable: true
         };
         const freeformDoc = CurrentUserUtils.GuestTarget || Docs.Create.FreeformDocument([], freeformOptions);
         const mainDoc = Docs.Create.StandardCollectionDockingDocument([{ doc: freeformDoc, initialWidth: 600, path: [Doc.UserDoc().myCatalog as Doc] }], { title: `Workspace ${workspaceCount}` }, id, "row");
diff --git a/src/client/views/PreviewCursor.tsx b/src/client/views/PreviewCursor.tsx
index 14b5b3fce..2ddca369a 100644
--- a/src/client/views/PreviewCursor.tsx
+++ b/src/client/views/PreviewCursor.tsx
@@ -46,7 +46,7 @@ export class PreviewCursor extends React.Component<{}> {
                 else if (re.test(e.clipboardData.getData("text/plain"))) {
                     const url = e.clipboardData.getData("text/plain");
                     undoBatch(() => PreviewCursor._addDocument(Docs.Create.WebDocument(url, {
-                        title: url, _width: 500, _height: 300,
+                        title: url, _width: 500, _height: 300, UseCors: true,
                         // nativeWidth: 300, nativeHeight: 472.5,
                         x: newPoint[0], y: newPoint[1]
                     })))();
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 296b2453b..50e3b73eb 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -755,8 +755,10 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
     }
 
     get layoutDoc() { return this._document && Doc.Layout(this._document); }
-    panelWidth = () => this.layoutDoc && this.layoutDoc.maxWidth ? Math.min(Math.max(NumCast(this.layoutDoc._width), NumCast(this.layoutDoc._nativeWidth)), this._panelWidth) : this._panelWidth;
-    panelHeight = () => this._panelHeight;
+    nativeAspect = () => this.nativeWidth() ? this.nativeWidth() / this.nativeHeight() : 0;
+    panelWidth = () => this.layoutDoc?.maxWidth ? Math.min(Math.max(NumCast(this.layoutDoc._width), NumCast(this.layoutDoc._nativeWidth)), this._panelWidth) :
+        (this.nativeAspect() && this.nativeAspect() < this._panelWidth / this._panelHeight ? this._panelHeight * this.nativeAspect() : this._panelWidth);
+    panelHeight = () => this.nativeAspect() && this.nativeAspect() > this._panelWidth / this._panelHeight ? this._panelWidth / this.nativeAspect() : this._panelHeight;
 
     nativeWidth = () => !this.layoutDoc!._fitWidth ? NumCast(this.layoutDoc!._nativeWidth) || this._panelWidth : 0;
     nativeHeight = () => !this.layoutDoc!._fitWidth ? NumCast(this.layoutDoc!._nativeHeight) || this._panelHeight : 0;
@@ -794,7 +796,7 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
         return Transform.Identity();
     }
     get previewPanelCenteringOffset() { return this.nativeWidth() ? (this._panelWidth - this.nativeWidth() * this.contentScaling()) / 2 : 0; }
-    get widthpercent() { return this.nativeWidth() ? `${(this.nativeWidth() * this.contentScaling()) / this.panelWidth() * 100}%` : undefined; }
+    get widthpercent() { return this.nativeWidth() ? `${(this.nativeWidth() * this.contentScaling()) / this._panelWidth * 100}%` : undefined; }
 
     addDocTab = (doc: Doc, location: string, libraryPath?: Doc[]) => {
         SelectionManager.DeselectAll();
@@ -832,8 +834,8 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
             ContentScaling={this.contentScaling}
             PanelWidth={this.panelWidth}
             PanelHeight={this.panelHeight}
-            NativeHeight={returnZero}
-            NativeWidth={returnZero}
+            NativeHeight={this.nativeHeight}
+            NativeWidth={this.nativeWidth}
             ScreenToLocalTransform={this.ScreenToLocalTransform}
             renderDepth={0}
             parentActive={returnTrue}
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index c199988c0..979e9e3f8 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -432,6 +432,7 @@ export class CollectionStackingView extends CollectionSubView(StackingDocument)
         if (!e.isPropagationStopped()) {
             const subItems: ContextMenuProps[] = [];
             subItems.push({ description: `${this.props.Document.fillColumn ? "Variable Size" : "Autosize"} Column`, event: () => this.props.Document.fillColumn = !this.props.Document.fillColumn, icon: "plus" });
+            subItems.push({ description: `${this.Document._autoHeight ? "Variable Height" : "Auto Height"}`, event: () => this.layoutDoc._autoHeight = !this.layoutDoc._autoHeight, icon: "plus" });
             ContextMenu.Instance.addItem({ description: "Options...", subitems: subItems, icon: "eye" });
         }
     }
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index d24ba6bb0..129b245b8 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -113,8 +113,8 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
             this.props.PanelWidth() / (this.contentBounds.r - this.contentBounds.x)) :
         this.Document.scale || 1)
 
-    private centeringShiftX = () => !this.nativeWidth && !this.isAnnotationOverlay ? this.props.PanelWidth() / 2 / this.parentScaling : 0;  // shift so pan position is at center of window for non-overlay collections
-    private centeringShiftY = () => !this.nativeHeight && !this.isAnnotationOverlay ? this.props.PanelHeight() / 2 / this.parentScaling : 0;// shift so pan position is at center of window for non-overlay collections
+    private centeringShiftX = () => !this.isAnnotationOverlay ? this.props.PanelWidth() / 2 / this.parentScaling / this.contentScaling : 0;  // shift so pan position is at center of window for non-overlay collections
+    private centeringShiftY = () => !this.isAnnotationOverlay ? this.props.PanelHeight() / 2 / this.parentScaling / this.contentScaling : 0;// shift so pan position is at center of window for non-overlay collections
     private getTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-this.borderWidth + 1, -this.borderWidth + 1).translate(-this.centeringShiftX(), -this.centeringShiftY()).transform(this.getLocalTransform());
     private getTransformOverlay = (): Transform => this.props.ScreenToLocalTransform().translate(-this.borderWidth + 1, -this.borderWidth + 1);
     private getContainerTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-this.borderWidth, -this.borderWidth);
@@ -340,12 +340,12 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
         this._hitCluster = this.props.Document.useClusters ? this.pickCluster(this.getTransform().transformPoint(e.clientX, e.clientY)) !== -1 : false;
         if (e.button === 0 && (!e.shiftKey || this._hitCluster) && !e.altKey && !e.ctrlKey && this.props.active(true)) {
 
-            if (!this.props.Document.aliasOf && !this.props.ContainingCollectionView) {
-                this.props.addDocTab(this.props.Document, "replace");
-                e.stopPropagation();
-                e.preventDefault();
-                return;
-            }
+            // if (!this.props.Document.aliasOf && !this.props.ContainingCollectionView) {
+            //     this.props.addDocTab(this.props.Document, "replace");
+            //     e.stopPropagation();
+            //     e.preventDefault();
+            //     return;
+            // }
             document.removeEventListener("pointermove", this.onPointerMove);
             document.removeEventListener("pointerup", this.onPointerUp);
             document.addEventListener("pointermove", this.onPointerMove);
@@ -1068,13 +1068,8 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
                 bounds: this.childDataProvider(entry[1].pair.layout, entry[1].replica)
             }));
 
-        // size contents according to dimensions of containing panel and current scale factor of collection
         if (this.props.isAnnotationOverlay) {
             this.props.Document.scale = Math.max(1, NumCast(this.props.Document.scale));
-        } else if (this.props.PanelWidth() && this.props.Document[WidthSym]() && !this.props.isAnnotationOverlay) {
-            this.props.Document.scale = this.props.PanelWidth() / this.props.Document[WidthSym]() * NumCast(this.props.Document.scale, 1);
-            this.props.Document._width = this.props.PanelWidth();
-            this.props.Document._height = this.props.PanelHeight();
         }
 
         return elements;
@@ -1129,6 +1124,11 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
             });
         }, "arrange contents");
     }
+    @undoBatch
+    @action
+    toggleNativeDimensions = () => {
+        Doc.toggleNativeDimensions(this.layoutDoc, this.props.ContentScaling(), this.props.NativeWidth(), this.props.NativeHeight());
+    }
 
     private thumbIdentifier?: number;
 
@@ -1138,6 +1138,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
         const optionItems: ContextMenuProps[] = options && "subitems" in options ? options.subitems : [];
 
         optionItems.push({ description: "reset view", event: () => { this.props.Document._panX = this.props.Document._panY = 0; this.props.Document.scale = 1; }, icon: "compress-arrows-alt" });
+        optionItems.push({ description: !this.layoutDoc._nativeWidth || !this.layoutDoc._nativeHeight ? "Freeze" : "Unfreeze", event: this.toggleNativeDimensions, icon: "snowflake" });
         optionItems.push({ description: `${this.Document._LODdisable ? "Enable LOD" : "Disable LOD"}`, event: () => this.Document._LODdisable = !this.Document._LODdisable, icon: "table" });
         optionItems.push({ description: `${this.fitToContent ? "Unset" : "Set"} Fit To Container`, event: () => this.Document._fitToBox = !this.fitToContent, icon: !this.fitToContent ? "expand-arrows-alt" : "compress-arrows-alt" });
         optionItems.push({ description: `${this.Document.useClusters ? "Uncluster" : "Use Clusters"}`, event: () => this.updateClusters(!this.Document.useClusters), icon: "braille" });
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index aca0433bb..6c9ade83f 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -648,18 +648,8 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
 
     @undoBatch
     @action
-    public static unfreezeNativeDimensions(layoutDoc: Doc) {
-        layoutDoc._nativeWidth = undefined;
-        layoutDoc._nativeHeight = undefined;
-    }
-
     toggleNativeDimensions = () => {
-        if (this.Document._nativeWidth || this.Document._nativeHeight) {
-            DocumentView.unfreezeNativeDimensions(this.layoutDoc);
-        }
-        else {
-            Doc.freezeNativeDimensions(this.layoutDoc, this.props.PanelWidth(), this.props.PanelHeight());
-        }
+        Doc.toggleNativeDimensions(this.layoutDoc, this.props.ContentScaling(), this.props.PanelWidth(), this.props.PanelHeight());
     }
 
     @undoBatch
@@ -735,10 +725,6 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
 
         let options = cm.findByDescription("Options...");
         const optionItems: ContextMenuProps[] = options && "subitems" in options ? options.subitems : [];
-        optionItems.push({ description: `${this.Document._chromeStatus !== "disabled" ? "Hide" : "Show"} Chrome`, event: () => this.Document._chromeStatus = (this.Document._chromeStatus !== "disabled" ? "disabled" : "enabled"), icon: "project-diagram" });
-        optionItems.push({ description: `${this.Document._autoHeight ? "Variable Height" : "Auto Height"}`, event: () => this.layoutDoc._autoHeight = !this.layoutDoc._autoHeight, icon: "plus" });
-        optionItems.push({ description: this.Document.lockedPosition ? "Unlock Position" : "Lock Position", event: this.toggleLockPosition, icon: BoolCast(this.Document.lockedPosition) ? "unlock" : "lock" });
-        optionItems.push({ description: this.Document.lockedTransform ? "Unlock Transform" : "Lock Transform", event: this.toggleLockTransform, icon: BoolCast(this.Document.lockedTransform) ? "unlock" : "lock" });
         if (!options) {
             options = { description: "Options...", subitems: optionItems, icon: "compass" };
             cm.addItem(options);
@@ -757,6 +743,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         onClicks.push({ description: "Edit onClick Script", event: () => UndoManager.RunInBatch(() => Doc.makeCustomViewClicked(this.props.Document, undefined, "onClick"), "edit onClick"), icon: "edit" });
         !existingOnClick && cm.addItem({ description: "OnClick...", subitems: onClicks, icon: "hand-point-right" });
 
+
         const funcs: ContextMenuProps[] = [];
         if (this.Document.onDragStart) {
             funcs.push({ description: "Drag an Alias", icon: "edit", event: () => this.Document.dragFactory && (this.Document.onDragStart = ScriptField.MakeFunction('getAlias(this.dragFactory)')) });
@@ -768,7 +755,9 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         const more = cm.findByDescription("More...");
         const moreItems: ContextMenuProps[] = more && "subitems" in more ? more.subitems : [];
         moreItems.push({ description: "Make View of Metadata Field", event: () => Doc.MakeMetadataFieldTemplate(this.props.Document, this.props.DataDoc), icon: "concierge-bell" });
-        moreItems.push({ description: !this.Document._nativeWidth || !this.Document._nativeHeight ? "Freeze" : "Unfreeze", event: this.toggleNativeDimensions, icon: "snowflake" });
+        moreItems.push({ description: `${this.Document._chromeStatus !== "disabled" ? "Hide" : "Show"} Chrome`, event: () => this.Document._chromeStatus = (this.Document._chromeStatus !== "disabled" ? "disabled" : "enabled"), icon: "project-diagram" });
+        moreItems.push({ description: this.Document.lockedTransform ? "Unlock Transform" : "Lock Transform", event: this.toggleLockTransform, icon: BoolCast(this.Document.lockedTransform) ? "unlock" : "lock" });
+        moreItems.push({ description: this.Document.lockedPosition ? "Unlock Position" : "Lock Position", event: this.toggleLockPosition, icon: BoolCast(this.Document.lockedPosition) ? "unlock" : "lock" });
 
         if (!ClientUtils.RELEASE) {
             // let copies: ContextMenuProps[] = [];
@@ -794,6 +783,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
             // a.download = `DocExport-${this.props.Document[Id]}.zip`;
             // a.click();
         });
+
         const recommender_subitems: ContextMenuProps[] = [];
 
         recommender_subitems.push({
@@ -826,6 +816,9 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         moreItems.push({ description: "Publish", event: () => DocUtils.Publish(this.props.Document, this.Document.title || "", this.props.addDocument, this.props.removeDocument), icon: "file" });
         moreItems.push({ description: "Undo Debug Test", event: () => UndoManager.TraceOpenBatches(), icon: "exclamation" });
         !more && cm.addItem({ description: "More...", subitems: moreItems, icon: "hand-point-right" });
+
+        cm.moveAfter(cm.findByDescription("More...")!, cm.findByDescription("OnClick...")!);
+
         runInAction(() => {
             if (!ClientUtils.RELEASE) {
                 const setWriteMode = (mode: DocServer.WriteMode) => {
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 4153c184e..d85373e98 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -157,21 +157,20 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps, ImageD
         const field = Cast(this.dataDoc[this.fieldKey], ImageField);
         if (field) {
             const funcs: ContextMenuProps[] = [];
-            funcs.push({ description: "Copy path", event: () => Utils.CopyText(field.url.href), icon: "expand-arrows-alt" });
             funcs.push({ description: "Rotate", event: this.rotate, icon: "expand-arrows-alt" });
-            funcs.push({
-                description: "Reset Native Dimensions", event: action(async () => {
-                    const curNW = NumCast(this.dataDoc[this.fieldKey + "-nativeWidth"]);
-                    const curNH = NumCast(this.dataDoc[this.fieldKey + "-nativeHeight"]);
-                    if (this.props.PanelWidth() / this.props.PanelHeight() > curNW / curNH) {
-                        this.dataDoc[this.fieldKey + "-nativeWidth"] = this.props.PanelHeight() * curNW / curNH;
-                        this.dataDoc[this.fieldKey + "-nativeHeight"] = this.props.PanelHeight();
-                    } else {
-                        this.dataDoc[this.fieldKey + "-nativeWidth"] = this.props.PanelWidth();
-                        this.dataDoc[this.fieldKey + "-nativeHeight"] = this.props.PanelWidth() * curNH / curNW;
-                    }
-                }), icon: "expand-arrows-alt"
-            });
+            // funcs.push({
+            //     description: "Reset Native Dimensions", event: action(async () => {
+            //         const curNW = NumCast(this.dataDoc[this.fieldKey + "-nativeWidth"]);
+            //         const curNH = NumCast(this.dataDoc[this.fieldKey + "-nativeHeight"]);
+            //         if (this.props.PanelWidth() / this.props.PanelHeight() > curNW / curNH) {
+            //             this.dataDoc[this.fieldKey + "-nativeWidth"] = this.props.PanelHeight() * curNW / curNH;
+            //             this.dataDoc[this.fieldKey + "-nativeHeight"] = this.props.PanelHeight();
+            //         } else {
+            //             this.dataDoc[this.fieldKey + "-nativeWidth"] = this.props.PanelWidth();
+            //             this.dataDoc[this.fieldKey + "-nativeHeight"] = this.props.PanelWidth() * curNH / curNW;
+            //         }
+            //     }), icon: "expand-arrows-alt"
+            // });
 
             const existingAnalyze = ContextMenu.Instance.findByDescription("Analyzers...");
             const modes: ContextMenuProps[] = existingAnalyze && "subitems" in existingAnalyze ? existingAnalyze.subitems : [];
@@ -181,6 +180,12 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps, ImageD
             !existingAnalyze && ContextMenu.Instance.addItem({ description: "Analyzers...", subitems: modes, icon: "hand-point-right" });
 
             ContextMenu.Instance.addItem({ description: "Options...", subitems: funcs, icon: "asterisk" });
+
+
+            const existingMore = ContextMenu.Instance.findByDescription("More...");
+            const mores: ContextMenuProps[] = existingMore && "subitems" in existingMore ? existingMore.subitems : [];
+            mores.push({ description: "Copy path", event: () => Utils.CopyText(field.url.href), icon: "expand-arrows-alt" });
+            !existingMore && ContextMenu.Instance.addItem({ description: "More...", subitems: mores, icon: "hand-point-right" });
         }
     }
 
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index 8239d6fdf..384a6e8a5 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -129,14 +129,12 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum
         }
     }
 
-    toggleNativeDimensions = () => {
+    toggleAnnotationMode = () => {
         if (!this.layoutDoc.isAnnotating) {
-            //DocumentView.unfreezeNativeDimensions(this.layoutDoc);
             this.layoutDoc.lockedTransform = false;
             this.layoutDoc.isAnnotating = true;
         }
         else {
-            //Doc.freezeNativeDimensions(this.layoutDoc, this.props.PanelWidth(), this.props.PanelHeight());
             this.layoutDoc.lockedTransform = true;
             this.layoutDoc.isAnnotating = false;
         }
@@ -158,10 +156,10 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum
                             <FontAwesomeIcon icon="caret-up" size="2x" />
                         </button>
                         <div className="webBox-buttons" style={{ display: this._collapsed ? "none" : "flex" }}>
-                            <div className="webBox-freeze" title={"Annotate"} style={{ background: this.layoutDoc.isAnnotating ? "lightBlue" : "gray" }} onClick={this.toggleNativeDimensions} >
+                            <div className="webBox-freeze" title={"Annotate"} style={{ background: this.layoutDoc.isAnnotating ? "lightBlue" : "gray" }} onClick={this.toggleAnnotationMode} >
                                 <FontAwesomeIcon icon={faPen} size={"2x"} />
                             </div>
-                            <div className="webBox-freeze" title={"Select"} style={{ background: !this.layoutDoc.isAnnotating ? "lightBlue" : "gray" }} onClick={this.toggleNativeDimensions} >
+                            <div className="webBox-freeze" title={"Select"} style={{ background: !this.layoutDoc.isAnnotating ? "lightBlue" : "gray" }} onClick={this.toggleAnnotationMode} >
                                 <FontAwesomeIcon icon={faMousePointer} size={"2x"} />
                             </div>
                             <input className="webpage-urlInput"
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index f3c277e20..2c51397eb 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -405,6 +405,11 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
         this.layoutDoc._sidebarWidthPercent = "" + 100 * (1 - (e.clientX - bounds.left) / bounds.width) + "%";
         return false;
     }
+    @undoBatch
+    @action
+    toggleNativeDimensions = () => {
+        Doc.toggleNativeDimensions(this.layoutDoc, this.props.ContentScaling(), this.props.NativeWidth(), this.props.NativeHeight());
+    }
 
     public static get DefaultLayout(): Doc | string | undefined {
         return Cast(Doc.UserDoc().defaultTextLayout, Doc, null) || StrCast(Doc.UserDoc().defaultTextLayout, null);
@@ -438,6 +443,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
                 Doc.AddDocToList(Cast(Doc.UserDoc()["template-notes"], Doc, null), "data", this.rootDoc);
             }, icon: "eye"
         });
+        //funcs.push({ description: `${this.Document._autoHeight ? "Variable Height" : "Auto Height"}`, event: () => this.layoutDoc._autoHeight = !this.layoutDoc._autoHeight, icon: "plus" });
+        funcs.push({ description: !this.layoutDoc._nativeWidth || !this.layoutDoc._nativeHeight ? "Freeze" : "Unfreeze", event: this.toggleNativeDimensions, icon: "snowflake" });
         funcs.push({ description: "Toggle Single Line", event: () => this.layoutDoc._singleLine = !this.layoutDoc._singleLine, icon: "expand-arrows-alt" });
         funcs.push({ description: "Toggle Sidebar", event: () => this.layoutDoc._showSidebar = !this.layoutDoc._showSidebar, icon: "expand-arrows-alt" });
         funcs.push({ description: "Toggle Dictation Icon", event: () => this.layoutDoc._showAudio = !this.layoutDoc._showAudio, icon: "expand-arrows-alt" });
@@ -649,10 +656,14 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
                 }
             }
         );
-        this._disposers.height = reaction(
+        this._disposers.autoHeight = reaction(
             () => [this.layoutDoc[WidthSym](), this.layoutDoc._autoHeight],
             () => this.tryUpdateHeight()
         );
+        this._disposers.height = reaction(
+            () => this.layoutDoc[HeightSym](),
+            height => height <= 20 && (this.layoutDoc._autoHeight = true)
+        );
 
         this.setupEditor(this.config, this.props.fieldKey);
 
@@ -1206,6 +1217,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
     render() {
         TraceMobx();
         const style: { [key: string]: any } = {};
+        const scale = this.props.ContentScaling() * NumCast(this.layoutDoc.scale, 1);
         const divKeys = ["width", "height", "background"];
         const replacer = (match: any, expr: string, offset: any, string: any) => { // bcz: this executes a script to convert a propery expression string:  { script }  into a value
             return ScriptField.MakeFunction(expr, { self: Doc.name, this: Doc.name })?.script.run({ self: this.rootDoc, this: this.layoutDoc }).result as string || "";
@@ -1258,6 +1270,10 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
                 <div className={`formattedTextBox-outer`} style={{ width: `calc(100% - ${this.sidebarWidthPercent})`, }} onScroll={this.onscrolled} ref={this._scrollRef}>
                     <div className={`formattedTextBox-inner${rounded}`} ref={this.createDropTarget}
                         style={{
+                            transform: `scale(${scale})`,
+                            transformOrigin: "top left",
+                            width: `${100 / scale}%`,
+                            height: `${100 / scale}%`,
                             padding: `${NumCast(this.layoutDoc._yMargin, this.props.yMargin || 0)}px  ${NumCast(this.layoutDoc._xMargin, this.props.xMargin || 0)}px`,
                             pointerEvents: ((this.layoutDoc.isLinkButton || this.props.onClick) && !this.props.isSelected()) ? "none" : undefined
                         }} />
diff --git a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
index 9ad5aafb8..a33717855 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
@@ -91,7 +91,7 @@ export class FormattedTextBoxComment {
                             (doc: Doc, followLinkLocation: string) => textBox.props.addDocTab(doc, e.ctrlKey ? "inTab" : followLinkLocation));
                     }
                 } else if (textBox && (FormattedTextBoxComment.tooltipText as any).href) {
-                    textBox.props.addDocTab(Docs.Create.WebDocument((FormattedTextBoxComment.tooltipText as any).href, { title: (FormattedTextBoxComment.tooltipText as any).href, _width: 200, _height: 400 }), "onRight");
+                    textBox.props.addDocTab(Docs.Create.WebDocument((FormattedTextBoxComment.tooltipText as any).href, { title: (FormattedTextBoxComment.tooltipText as any).href, _width: 200, _height: 400, UseCors: true }), "onRight");
                 }
                 keep && textBox && FormattedTextBoxComment.start !== undefined && textBox.adoptAnnotation(
                     FormattedTextBoxComment.start, FormattedTextBoxComment.end, FormattedTextBoxComment.mark);
diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts
index e0627fb37..a1e1e11b1 100644
--- a/src/new_fields/Doc.ts
+++ b/src/new_fields/Doc.ts
@@ -20,7 +20,6 @@ import { deleteProperty, getField, getter, makeEditable, makeReadOnly, setter, u
 import { Docs, DocumentOptions } from "../client/documents/Documents";
 import { PdfField, VideoField, AudioField, ImageField } from "./URLField";
 import { LinkManager } from "../client/util/LinkManager";
-import { string32 } from "../../deploy/assets/pdf.worker";
 
 export namespace Field {
     export function toKeyValueString(doc: Doc, key: string): string {
@@ -936,19 +935,28 @@ export namespace Doc {
             }
         }
     }
-
-    export function freezeNativeDimensions(layoutDoc: Doc, width: number, height: number): void {
-        layoutDoc._autoHeight = false;
-        if (!layoutDoc._nativeWidth) {
-            layoutDoc._nativeWidth = NumCast(layoutDoc._width, width);
-            layoutDoc._nativeHeight = NumCast(layoutDoc._height, height);
-        }
-    }
     export function assignDocToField(doc: Doc, field: string, id: string) {
         DocServer.GetRefField(id).then(layout => layout instanceof Doc && (doc[field] = layout));
         return id;
     }
 
+    export function toggleNativeDimensions(layoutDoc: Doc, contentScale: number, panelWidth: number, panelHeight: number) {
+        runInAction(() => {
+            if (layoutDoc._nativeWidth || layoutDoc._nativeHeight) {
+                layoutDoc.scale = NumCast(layoutDoc.scale, 1) * contentScale;
+                layoutDoc._nativeWidth = undefined;
+                layoutDoc._nativeHeight = undefined;
+            }
+            else {
+                layoutDoc._autoHeight = false;
+                if (!layoutDoc._nativeWidth) {
+                    layoutDoc._nativeWidth = NumCast(layoutDoc._width, panelWidth);
+                    layoutDoc._nativeHeight = NumCast(layoutDoc._height, panelHeight);
+                }
+            }
+        });
+    }
+
     export function isDocPinned(doc: Doc) {
         //add this new doc to props.Document
         const curPres = Cast(Doc.UserDoc().activePresentation, Doc) as Doc;
diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts
index bebf77a8c..b6ff10bab 100644
--- a/src/server/authentication/models/current_user_utils.ts
+++ b/src/server/authentication/models/current_user_utils.ts
@@ -315,7 +315,7 @@ export class CurrentUserUtils {
                 { _width: 250, _height: 250, title: "container" });
         }
         if (doc.emptyWebpage === undefined) {
-            doc.emptyWebpage = Docs.Create.WebDocument("", { title: "New Webpage", _width: 600 });
+            doc.emptyWebpage = Docs.Create.WebDocument("", { title: "New Webpage", _width: 600, UseCors: true });
         }
         return [
             { title: "Drag a collection", label: "Col", icon: "folder", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory, true)', dragFactory: doc.emptyCollection as Doc },
-- 
cgit v1.2.3-70-g09d2


From 4bd011dcc6a3f009fa10932c7c6ca1932b784fde Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Tue, 12 May 2020 17:21:48 -0400
Subject: fixed copy paste of documents in freeform collections.

---
 src/client/views/GlobalKeyHandler.ts |  4 ++--
 src/client/views/PreviewCursor.tsx   | 11 ++++++-----
 2 files changed, 8 insertions(+), 7 deletions(-)

(limited to 'src/client/views/PreviewCursor.tsx')

diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts
index 1b16b15bb..b52a0063b 100644
--- a/src/client/views/GlobalKeyHandler.ts
+++ b/src/client/views/GlobalKeyHandler.ts
@@ -263,8 +263,8 @@ export default class KeyManager {
             case "c":
                 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(":");
+                    const pt = SelectionManager.SelectedDocuments()[0].props.ScreenToLocalTransform().transformPoint(bds.x + (bds.r - bds.x) / 2, bds.y + (bds.b - bds.y) / 2);
+                    const text = `__DashDocId(${pt?.[0] || 0},${pt?.[1] || 0}):` + SelectionManager.SelectedDocuments().map(dv => dv.Document[Id]).join(":");
                     SelectionManager.SelectedDocuments().length && navigator.clipboard.writeText(text);
                     stopPropagation = false;
                     preventDefault = false;
diff --git a/src/client/views/PreviewCursor.tsx b/src/client/views/PreviewCursor.tsx
index 2ddca369a..f7a7944c9 100644
--- a/src/client/views/PreviewCursor.tsx
+++ b/src/client/views/PreviewCursor.tsx
@@ -7,8 +7,8 @@ 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';
+import { NumCast } from '../../new_fields/Types';
 
 @observer
 export class PreviewCursor extends React.Component<{}> {
@@ -57,22 +57,23 @@ export class PreviewCursor extends React.Component<{}> {
                     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.MakeClone(doc);
-                            alias.x = newPoint[0] + NumCast(doc.x) - center[0];
-                            alias.y = newPoint[1] + NumCast(doc.y) - center[1];
+                            const deltaX = NumCast(doc.x) - ptx;
+                            const deltaY = NumCast(doc.y) - pty;
+                            alias.x = newPoint[0] + deltaX;
+                            alias.y = newPoint[1] + deltaY;
                             list.push(alias);
                         }
                         if (count === docids.length) {
                             undoBatch(() => PreviewCursor._addDocument(list))();
                         }
                     }));
-
+                    e.stopPropagation();
                 } else {
                     // creates text document
                     undoBatch(() => PreviewCursor._addLiveTextDoc(Docs.Create.TextDocument("", {
-- 
cgit v1.2.3-70-g09d2

