From a560acaf539c058a2918a12e5de5061cca4b19e2 Mon Sep 17 00:00:00 2001
From: Tyler Schicke <tyler_schicke@brown.edu>
Date: Mon, 29 Jul 2019 16:10:13 -0400
Subject: Bunch of fixes

---
 src/client/views/nodes/ImageBox.tsx | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

(limited to 'src/client/views/nodes/ImageBox.tsx')

diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 29a76b0c8..82af4b4ca 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -96,7 +96,11 @@ export class ImageBox extends DocComponent<FieldViewProps, ImageDocument>(ImageD
                     this.props.Document.width = drop.width;
                     this.props.Document.height = drop.height;
                     Doc.GetProto(this.props.Document).type = DocumentType.TEMPLATE;
-                    this.props.Document.layout = temp;
+                    if (this.props.DataDoc && this.props.DataDoc.layout === this.props.Document) {
+                        this.props.DataDoc.layout = temp;
+                    } else {
+                        this.props.Document.layout = temp;
+                    }
                     e.stopPropagation();
                 } else if (de.mods === "AltKey" && /*this.dataDoc !== this.props.Document &&*/ drop.data instanceof ImageField) {
                     Doc.GetProto(this.dataDoc)[this.props.fieldKey] = new ImageField(drop.data.url);
-- 
cgit v1.2.3-70-g09d2


From 06dfb537826e8b1642783a9c4ab2514fd7da2fe3 Mon Sep 17 00:00:00 2001
From: Tyler Schicke <tyler_schicke@brown.edu>
Date: Mon, 29 Jul 2019 16:53:52 -0400
Subject: More fixes

---
 src/client/views/collections/CollectionDockingView.tsx             | 2 +-
 src/client/views/collections/CollectionStackingView.scss           | 1 +
 src/client/views/collections/CollectionStackingViewFieldColumn.tsx | 4 ++--
 src/client/views/nodes/ImageBox.tsx                                | 2 +-
 4 files changed, 5 insertions(+), 4 deletions(-)

(limited to 'src/client/views/nodes/ImageBox.tsx')

diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 1859ebee7..d7b5262b1 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -561,7 +561,7 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
         }
         return Transform.Identity();
     }
-    get previewPanelCenteringOffset() { return this.nativeWidth && !BoolCast(this._document!.ignoreAspect) ? (this._panelWidth - this.nativeWidth() * this.contentScaling()) / 2 : 0; }
+    get previewPanelCenteringOffset() { return this.nativeWidth && !BoolCast(this._document!.ignoreAspect) ? (this._panelWidth - this.nativeWidth()) / 2 : 0; }
 
     addDocTab = (doc: Doc, dataDoc: Doc | undefined, location: string) => {
         if (doc.dockingConfig) {
diff --git a/src/client/views/collections/CollectionStackingView.scss b/src/client/views/collections/CollectionStackingView.scss
index 004b57eff..2bb36c825 100644
--- a/src/client/views/collections/CollectionStackingView.scss
+++ b/src/client/views/collections/CollectionStackingView.scss
@@ -74,6 +74,7 @@
         transform-origin: top left;
         grid-column-end: span 1;
         height: 100%;
+        margin: auto;
     }
 
     .collectionStackingView-sectionHeader {
diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
index 71c4d9f0c..b5dbc1a22 100644
--- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
+++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
@@ -239,7 +239,7 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
         };
         let headingView = this.props.headingObject ?
             <div key={heading} className="collectionStackingView-sectionHeader" ref={this._headerRef}
-                style={{ width: (style.columnWidth) / (uniqueHeadings.length + (this.props.parent.props.CollectionView.props.Document.chromeStatus !== 'disabled' ? 1 : 0)) }}>
+                style={{ width: (style.columnWidth) / ((uniqueHeadings.length + (this.props.parent.props.CollectionView.props.Document.chromeStatus !== 'disabled' ? 1 : 0)) || 1) }}>
                 {/* the default bucket (no key value) has a tooltip that describes what it is.
                     Further, it does not have a color and cannot be deleted. */}
                 <div className="collectionStackingView-sectionHeader-subCont" onPointerDown={this.headerDown}
@@ -261,7 +261,7 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
             </div> : (null);
         for (let i = 0; i < cols; i++) templatecols += `${style.columnWidth}px `;
         return (
-            <div key={heading} style={{ width: `${100 / (uniqueHeadings.length + (this.props.parent.props.CollectionView.props.Document.chromeStatus !== 'disabled' ? 1 : 0))}%`, background: this._background }}
+            <div key={heading} style={{ width: `${100 / ((uniqueHeadings.length + (this.props.parent.props.CollectionView.props.Document.chromeStatus !== 'disabled' ? 1 : 0)) || 1)}%`, background: this._background }}
                 ref={this.createColumnDropRef} onPointerEnter={this.pointerEntered} onPointerLeave={this.pointerLeave}>
                 {headingView}
                 <div key={`${heading}-stack`} className={`collectionStackingView-masonry${singleColumn ? "Single" : "Grid"}`}
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 82af4b4ca..d4e0eaf98 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -291,7 +291,7 @@ export class ImageBox extends DocComponent<FieldViewProps, ImageDocument>(ImageD
                 let aspect = size.height / size.width;
                 let rotation = NumCast(this.dataDoc.rotation) % 180;
                 if (rotation === 90 || rotation === 270) aspect = 1 / aspect;
-                if (Math.abs(layoutdoc[HeightSym]() / layoutdoc[WidthSym]() - aspect) > 0.01) {
+                if (Math.abs(NumCast(layoutdoc.height) - size.height) > 1 || Math.abs(NumCast(layoutdoc.width) - size.width) > 1) {
                     setTimeout(action(() => {
                         layoutdoc.height = layoutdoc[WidthSym]() * aspect;
                         layoutdoc.nativeHeight = size.height;
-- 
cgit v1.2.3-70-g09d2


From 5248a770123e312e1684d7147ecb7118dd6ef1e7 Mon Sep 17 00:00:00 2001
From: Sam Wilkins <samwilkins333@gmail.com>
Date: Tue, 30 Jul 2019 01:24:37 -0400
Subject: tag generation and faces on extensionDoc

---
 src/client/cognitive_services/CognitiveServices.ts | 40 ++++--------------
 src/client/views/nodes/FaceRectangles.tsx          |  2 +-
 src/client/views/nodes/ImageBox.tsx                | 49 +++++++++++++++++++---
 3 files changed, 54 insertions(+), 37 deletions(-)

(limited to 'src/client/views/nodes/ImageBox.tsx')

diff --git a/src/client/cognitive_services/CognitiveServices.ts b/src/client/cognitive_services/CognitiveServices.ts
index bbc438a9b..076907f09 100644
--- a/src/client/cognitive_services/CognitiveServices.ts
+++ b/src/client/cognitive_services/CognitiveServices.ts
@@ -42,7 +42,7 @@ export enum Confidence {
  */
 export namespace CognitiveServices {
 
-    const executeQuery = async <D, R>(service: Service, manager: APIManager<D>, data: D): Promise<Opt<R>> => {
+    const ExecuteQuery = async <D, R>(service: Service, manager: APIManager<D>, data: D): Promise<Opt<R>> => {
         return fetch(Utils.prepend(`${RouteStore.cognitiveServices}/${service}`)).then(async response => {
             let apiKey = await response.text();
             if (!apiKey) {
@@ -103,15 +103,15 @@ export namespace CognitiveServices {
                 return request.post(options);
             },
 
-            analyzer: async (target: Doc, keys: string[], service: Service, converter: Converter) => {
+            analyzer: async (target: Doc, keys: string[], url: string, service: Service, converter: Converter) => {
                 let batch = UndoManager.StartBatch("Image Analysis");
-                let imageData = Cast(target.data, ImageField);
+
                 let storageKey = keys[0];
-                if (!imageData || await Cast(target[storageKey], Doc)) {
+                if (!url || await Cast(target[storageKey], Doc)) {
                     return;
                 }
                 let toStore: any;
-                let results = await executeQuery<string, any>(service, Manager, imageData.url.href);
+                let results = await ExecuteQuery<string, any>(service, Manager, url);
                 if (!results) {
                     toStore = "Cognitive Services could not process the given image URL.";
                 } else {
@@ -122,6 +122,7 @@ export namespace CognitiveServices {
                     }
                 }
                 target[storageKey] = toStore;
+
                 batch.end();
             }
 
@@ -129,31 +130,6 @@ export namespace CognitiveServices {
 
         export type Face = { faceAttributes: any, faceId: string, faceRectangle: Rectangle };
 
-        export const generateMetadata = async (target: Doc, threshold: Confidence = Confidence.Excellent) => {
-            let converter = (results: any) => {
-                let tagDoc = new Doc;
-                results.tags.map((tag: Tag) => {
-                    let sanitized = tag.name.replace(" ", "_");
-                    let script = `return (${tag.confidence} >= this.confidence) ? ${tag.confidence} : "${ComputedField.undefined}"`;
-                    let computed = CompileScript(script, { params: { this: "Doc" } });
-                    computed.compiled && (tagDoc[sanitized] = new ComputedField(computed));
-                });
-                tagDoc.title = "Generated Tags";
-                tagDoc.confidence = threshold;
-                return tagDoc;
-            };
-            Manager.analyzer(target, ["generatedTags"], Service.ComputerVision, converter);
-        };
-
-        export const extractFaces = async (target: Doc) => {
-            let converter = (results: any) => {
-                let faceDocs = new List<Doc>();
-                results.map((face: Face) => faceDocs.push(Docs.Get.DocumentHierarchyFromJson(face, `Face: ${face.faceId}`)!));
-                return faceDocs;
-            };
-            Manager.analyzer(target, ["faces"], Service.Face, converter);
-        };
-
     }
 
     export namespace Inking {
@@ -209,7 +185,8 @@ export namespace CognitiveServices {
 
             analyzer: async (target: Doc, keys: string[], inkData: InkData) => {
                 let batch = UndoManager.StartBatch("Ink Analysis");
-                let results = await executeQuery<InkData, any>(Service.Handwriting, Manager, inkData);
+
+                let results = await ExecuteQuery<InkData, any>(Service.Handwriting, Manager, inkData);
                 if (results) {
                     results.recognitionUnits && (results = results.recognitionUnits);
                     target[keys[0]] = Docs.Get.DocumentHierarchyFromJson(results, "Ink Analysis");
@@ -217,6 +194,7 @@ export namespace CognitiveServices {
                     let individualWords = recognizedText.filter((text: string) => text && text.split(" ").length === 1);
                     target[keys[1]] = individualWords.join(" ");
                 }
+
                 batch.end();
             }
 
diff --git a/src/client/views/nodes/FaceRectangles.tsx b/src/client/views/nodes/FaceRectangles.tsx
index 3570531b2..acf1aced3 100644
--- a/src/client/views/nodes/FaceRectangles.tsx
+++ b/src/client/views/nodes/FaceRectangles.tsx
@@ -20,7 +20,7 @@ export interface RectangleTemplate {
 export default class FaceRectangles extends React.Component<FaceRectanglesProps> {
 
     render() {
-        let faces = DocListCast(Doc.GetProto(this.props.document).faces);
+        let faces = DocListCast(this.props.document.faces);
         let templates: RectangleTemplate[] = faces.map(faceDoc => {
             let rectangle = Cast(faceDoc.faceRectangle, Doc) as Doc;
             let style = {
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 29a76b0c8..5554475ec 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -25,9 +25,12 @@ import { Docs, DocumentType } from '../../documents/Documents';
 import { DocServer } from '../../DocServer';
 import { Font } from '@react-pdf/renderer';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { CognitiveServices } from '../../cognitive_services/CognitiveServices';
+import { CognitiveServices, Service, Tag, Confidence } from '../../cognitive_services/CognitiveServices';
 import FaceRectangles from './FaceRectangles';
 import { faEye } from '@fortawesome/free-regular-svg-icons';
+import { ComputedField } from '../../../new_fields/ScriptField';
+import { CompileScript } from '../../util/Scripting';
+import { thisExpression } from 'babel-types';
 var requestImageSize = require('../../util/request-image-size');
 var path = require('path');
 const { Howl } = require('howler');
@@ -226,20 +229,56 @@ export class ImageBox extends DocComponent<FieldViewProps, ImageDocument>(ImageD
             funcs.push({ description: "Rotate", event: this.rotate, icon: "expand-arrows-alt" });
 
             let modes: ContextMenuProps[] = [];
-            let dataDoc = Doc.GetProto(this.props.Document);
-            modes.push({ description: "Generate Tags", event: () => CognitiveServices.Image.generateMetadata(dataDoc), icon: "tag" });
-            modes.push({ description: "Find Faces", event: () => CognitiveServices.Image.extractFaces(dataDoc), icon: "camera" });
+            modes.push({ description: "Generate Tags", event: this.generateMetadata, icon: "tag" });
+            modes.push({ description: "Find Faces", event: this.extractFaces, icon: "camera" });
 
             ContextMenu.Instance.addItem({ description: "Image Funcs...", subitems: funcs, icon: "asterisk" });
             ContextMenu.Instance.addItem({ description: "Analyze...", subitems: modes, icon: "eye" });
         }
     }
 
+    extractFaces = () => {
+        let converter = (results: any) => {
+            let faceDocs = new List<Doc>();
+            results.map((face: CognitiveServices.Image.Face) => faceDocs.push(Docs.Get.DocumentHierarchyFromJson(face, `Face: ${face.faceId}`)!));
+            return faceDocs;
+        };
+        CognitiveServices.Image.Manager.analyzer(this.extensionDoc, ["faces"], this.url, Service.Face, converter);
+    }
+
+    generateMetadata = (threshold: Confidence = Confidence.Excellent) => {
+        let converter = (results: any) => {
+            let tagDoc = new Doc;
+            let tagsList = new List();
+            results.tags.map((tag: Tag) => {
+                tagsList.push(tag.name);
+                let sanitized = tag.name.replace(" ", "_");
+                let script = `return (${tag.confidence} >= this.confidence) ? ${tag.confidence} : "${ComputedField.undefined}"`;
+                let computed = CompileScript(script, { params: { this: "Doc" } });
+                computed.compiled && (tagDoc[sanitized] = new ComputedField(computed));
+            });
+            this.extensionDoc.generatedTags = tagsList;
+            tagDoc.title = "Generated Tags Doc";
+            tagDoc.confidence = threshold;
+            return tagDoc;
+        };
+        CognitiveServices.Image.Manager.analyzer(this.extensionDoc, ["generatedTagsDoc"], this.url, Service.ComputerVision, converter);
+    }
+
     @action
     onDotDown(index: number) {
         this.Document.curPage = index;
     }
 
+    @computed get fieldExtensionDoc() {
+        return Doc.resolvedFieldDataDoc(this.props.DataDoc ? this.props.DataDoc : this.props.Document, this.props.fieldKey, "true");
+    }
+
+    @computed private get url() {
+        let data = Cast(Doc.GetProto(this.props.Document).data, ImageField);
+        return data ? data.url.href : undefined;
+    }
+
     dots(paths: string[]) {
         let nativeWidth = FieldValue(this.Document.nativeWidth, 1);
         let dist = Math.min(nativeWidth / paths.length, 40);
@@ -394,7 +433,7 @@ export class ImageBox extends DocComponent<FieldViewProps, ImageDocument>(ImageD
                         style={{ color: [DocListCast(this.extensionDoc.audioAnnotations).length ? "blue" : "gray", "green", "red"][this._audioState] }} icon={faFileAudio} size="sm" />
                 </div>
                 {/* {this.lightbox(paths)} */}
-                <FaceRectangles document={this.props.Document} color={"#0000FF"} backgroundColor={"#0000FF"} />
+                <FaceRectangles document={this.extensionDoc} color={"#0000FF"} backgroundColor={"#0000FF"} />
             </div>);
     }
 }
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2


From a268800c9d743e94c9395dc1d34809bb55c3ceab Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Wed, 31 Jul 2019 00:05:39 -0400
Subject: added alt-drag-drop for applying template to items in a collection

---
 src/client/views/collections/CollectionSubView.tsx | 15 ++++++++++-----
 src/client/views/nodes/ImageBox.tsx                | 12 +-----------
 src/new_fields/Doc.ts                              | 13 +++++++++++++
 3 files changed, 24 insertions(+), 16 deletions(-)

(limited to 'src/client/views/nodes/ImageBox.tsx')

diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 7386eaba6..077f3f941 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -1,13 +1,15 @@
 import { action, computed } from "mobx";
 import * as rp from 'request-promise';
 import CursorField from "../../../new_fields/CursorField";
-import { Doc, DocListCast, Opt } from "../../../new_fields/Doc";
+import { Doc, DocListCast } from "../../../new_fields/Doc";
 import { Id } from "../../../new_fields/FieldSymbols";
 import { List } from "../../../new_fields/List";
 import { listSpec } from "../../../new_fields/Schema";
+import { ScriptField } from "../../../new_fields/ScriptField";
 import { BoolCast, Cast } from "../../../new_fields/Types";
 import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils";
 import { RouteStore } from "../../../server/RouteStore";
+import { Utils } from "../../../Utils";
 import { DocServer } from "../../DocServer";
 import { Docs, DocumentOptions, DocumentType } from "../../documents/Documents";
 import { DragManager } from "../../util/DragManager";
@@ -19,10 +21,6 @@ import { CollectionPDFView } from "./CollectionPDFView";
 import { CollectionVideoView } from "./CollectionVideoView";
 import { CollectionView } from "./CollectionView";
 import React = require("react");
-import { MainView } from "../MainView";
-import { Utils } from "../../../Utils";
-import { ScriptField } from "../../../new_fields/ScriptField";
-import { CompileScript } from "../../util/Scripting";
 
 export interface CollectionViewProps extends FieldViewProps {
     addDocument: (document: Doc, allowDuplicates?: boolean) => boolean;
@@ -115,6 +113,13 @@ export function CollectionSubView<T>(schemaCtor: (doc: Doc) => T) {
         @action
         protected drop(e: Event, de: DragManager.DropEvent): boolean {
             if (de.data instanceof DragManager.DocumentDragData) {
+                if (de.mods === "AltKey" && de.data.draggedDocuments.length) {
+                    this.childDocs.map(doc =>
+                        Doc.ApplyTemplateTo(de.data.draggedDocuments[0], doc, undefined)
+                    );
+                    e.stopPropagation();
+                    return true;
+                }
                 let added = false;
                 if (de.data.dropAction || de.data.userDropAction) {
                     added = de.data.droppedDocuments.reduce((added: boolean, d) => this.props.addDocument(d) || added, false);
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index dbe545048..b60ef41fd 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -93,17 +93,7 @@ export class ImageBox extends DocComponent<FieldViewProps, ImageDocument>(ImageD
         if (de.data instanceof DragManager.DocumentDragData) {
             de.data.droppedDocuments.forEach(action((drop: Doc) => {
                 if (de.mods === "CtrlKey") {
-                    let temp = Doc.MakeDelegate(drop);
-                    this.props.Document.nativeWidth = Doc.GetProto(this.props.Document).nativeWidth = undefined;
-                    this.props.Document.nativeHeight = Doc.GetProto(this.props.Document).nativeHeight = undefined;
-                    this.props.Document.width = drop.width;
-                    this.props.Document.height = drop.height;
-                    Doc.GetProto(this.props.Document).type = DocumentType.TEMPLATE;
-                    if (this.props.DataDoc && this.props.DataDoc.layout === this.props.Document) {
-                        this.props.DataDoc.layout = temp;
-                    } else {
-                        this.props.Document.layout = temp;
-                    }
+                    Doc.ApplyTemplateTo(drop, this.props.Document, this.props.DataDoc);
                     e.stopPropagation();
                 } else if (de.mods === "AltKey" && /*this.dataDoc !== this.props.Document &&*/ drop.data instanceof ImageField) {
                     Doc.GetProto(this.dataDoc)[this.props.fieldKey] = new ImageField(drop.data.url);
diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts
index 59314783b..dab0f9070 100644
--- a/src/new_fields/Doc.ts
+++ b/src/new_fields/Doc.ts
@@ -462,6 +462,19 @@ export namespace Doc {
         otherdoc.type = DocumentType.TEMPLATE;
         return otherdoc;
     }
+    export function ApplyTemplateTo(templateDoc: Doc, target: Doc, targetData?: Doc) {
+        let temp = Doc.MakeDelegate(templateDoc);
+        target.nativeWidth = Doc.GetProto(target).nativeWidth = undefined;
+        target.nativeHeight = Doc.GetProto(target).nativeHeight = undefined;
+        target.width = templateDoc.width;
+        target.height = templateDoc.height;
+        Doc.GetProto(target).type = DocumentType.TEMPLATE;
+        if (targetData && targetData.layout === target) {
+            targetData.layout = temp;
+        } else {
+            target.layout = temp;
+        }
+    }
 
     export function MakeTemplate(fieldTemplate: Doc, metaKey: string, templateDataDoc: Doc) {
         // move data doc fields to layout doc as needed (nativeWidth/nativeHeight, data, ??)
-- 
cgit v1.2.3-70-g09d2


From f450ba6cea4fe0e9e2c83af68177e3a70aa9a499 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Wed, 31 Jul 2019 10:03:15 -0400
Subject: fixes for templates and pivot viewer.

---
 src/client/views/nodes/FormattedTextBox.tsx |  3 ++-
 src/client/views/nodes/ImageBox.tsx         |  2 +-
 src/new_fields/Doc.ts                       | 37 +++++++++++++++++++----------
 3 files changed, 27 insertions(+), 15 deletions(-)

(limited to 'src/client/views/nodes/ImageBox.tsx')

diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 87b1d43c1..e076efe18 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -141,7 +141,8 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
 
     @computed get extensionDoc() { return Doc.resolvedFieldDataDoc(this.dataDoc, this.props.fieldKey, "dummy"); }
 
-    @computed get dataDoc() { return BoolCast(this.props.Document.isTemplate) && this.props.DataDoc ? this.props.DataDoc : Doc.GetProto(this.props.Document); }
+    @computed get dataDoc() { return this.props.DataDoc && (BoolCast(this.props.Document.isTemplate) || BoolCast(this.props.DataDoc.isTemplate) || this.props.DataDoc.layout === this.props.Document) ? this.props.DataDoc : Doc.GetProto(this.props.Document); }
+
 
     paste = (e: ClipboardEvent) => {
         if (e.clipboardData && this._editorView) {
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index b60ef41fd..9a0615d68 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -68,7 +68,7 @@ export class ImageBox extends DocComponent<FieldViewProps, ImageDocument>(ImageD
     private dropDisposer?: DragManager.DragDropDisposer;
 
 
-    @computed get dataDoc() { return BoolCast(this.props.Document.isTemplate) && this.props.DataDoc ? this.props.DataDoc : this.props.Document; }
+    @computed get dataDoc() { return this.props.DataDoc && (BoolCast(this.props.Document.isTemplate) || BoolCast(this.props.DataDoc.isTemplate) || this.props.DataDoc.layout === this.props.Document) ? this.props.DataDoc : this.props.Document; }
 
 
     protected createDropTarget = (ele: HTMLDivElement) => {
diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts
index c889fae31..5f9df786e 100644
--- a/src/new_fields/Doc.ts
+++ b/src/new_fields/Doc.ts
@@ -1,4 +1,4 @@
-import { observable, action } from "mobx";
+import { observable, action, runInAction } from "mobx";
 import { serializable, primitive, map, alias, list, PropSchema, custom } from "serializr";
 import { autoObject, SerializationHelper, Deserializable, afterDocDeserialize } from "../client/util/SerializationHelper";
 import { DocServer } from "../client/DocServer";
@@ -511,18 +511,29 @@ export namespace Doc {
         setTimeout(() => fieldTemplate.proto = templateDataDoc);
     }
 
-    export async function ToggleDetailLayout(d: Doc) {
-        let miniLayout = await PromiseValue(d.miniLayout);
-        let detailLayout = await PromiseValue(d.detailedLayout);
-        d.layout !== miniLayout ? miniLayout && (d.layout = d.miniLayout) : detailLayout && (d.layout = detailLayout);
-        if (d.layout === detailLayout) Doc.GetProto(d).nativeWidth = Doc.GetProto(d).nativeHeight = undefined;
+    export function ToggleDetailLayout(d: Doc) {
+        runInAction(async () => {
+            let miniLayout = await PromiseValue(d.miniLayout);
+            let detailLayout = await PromiseValue(d.detailedLayout);
+            d.layout !== miniLayout ? miniLayout && (d.layout = d.miniLayout) : detailLayout && (d.layout = detailLayout);
+            if (d.layout === detailLayout) Doc.GetProto(d).nativeWidth = Doc.GetProto(d).nativeHeight = undefined;
+        });
     }
-    export async function UseDetailLayout(d: Doc) {
-        let miniLayout = await PromiseValue(d.miniLayout);
-        let detailLayout = await PromiseValue(d.detailedLayout);
-        if (miniLayout && d.layout === miniLayout && detailLayout) {
-            d.layout = detailLayout;
-            d.nativeWidth = d.nativeHeight = undefined;
-        }
+    export function UseDetailLayout(d: Doc) {
+        runInAction(async () => {
+            let detailLayout1 = await PromiseValue(d.detailedLayout);
+            let detailLayout = await PromiseValue(d.detailedLayout);
+            if (detailLayout) {
+                d.layout = detailLayout;
+                d.nativeWidth = d.nativeHeight = undefined;
+                if (detailLayout instanceof Doc) {
+                    let delegDetailLayout = Doc.MakeDelegate(detailLayout) as Doc;
+                    d.layout = delegDetailLayout;
+                    let subDetailLayout1 = await PromiseValue(delegDetailLayout.detailedLayout);
+                    let subDetailLayout = await PromiseValue(delegDetailLayout.detailedLayout);
+                    delegDetailLayout.layout = subDetailLayout;
+                }
+            }
+        });
     }
 }
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2


From 40db4e50aaef7e012f652c8637e101b5a1a99d47 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Thu, 1 Aug 2019 16:21:29 -0400
Subject: fixed errors.

---
 src/client/views/TemplateMenu.tsx   |  2 +-
 src/client/views/nodes/ImageBox.tsx | 31 ++++++++++++++-----------------
 2 files changed, 15 insertions(+), 18 deletions(-)

(limited to 'src/client/views/nodes/ImageBox.tsx')

diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx
index c413650f0..e654a0644 100644
--- a/src/client/views/TemplateMenu.tsx
+++ b/src/client/views/TemplateMenu.tsx
@@ -39,7 +39,7 @@ export interface TemplateMenuProps {
 @observer
 export class TemplateMenu extends React.Component<TemplateMenuProps> {
     @observable private _hidden: boolean = true;
-    dragRef = React.createRef<HTMLDivElement>();
+    dragRef = React.createRef<HTMLUListElement>();
 
     constructor(props: TemplateMenuProps) {
         super(props);
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 9a0615d68..17dc4184a 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -1,42 +1,39 @@
 import { library } from '@fortawesome/fontawesome-svg-core';
-import { faImage, faFileAudio, faPaintBrush, faAsterisk } from '@fortawesome/free-solid-svg-icons';
-import { action, observable, computed, runInAction } from 'mobx';
+import { faEye } from '@fortawesome/free-regular-svg-icons';
+import { faAsterisk, faFileAudio, faImage, faPaintBrush } from '@fortawesome/free-solid-svg-icons';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { action, computed, observable, runInAction } from 'mobx';
 import { observer } from "mobx-react";
 import Lightbox from 'react-image-lightbox';
 import 'react-image-lightbox/style.css'; // This only needs to be imported once in your app
-import { Doc, HeightSym, WidthSym, DocListCast } from '../../../new_fields/Doc';
+import { Doc, DocListCast, HeightSym, WidthSym } from '../../../new_fields/Doc';
 import { List } from '../../../new_fields/List';
 import { createSchema, listSpec, makeInterface } from '../../../new_fields/Schema';
-import { Cast, FieldValue, NumCast, StrCast, BoolCast } from '../../../new_fields/Types';
-import { ImageField, AudioField } from '../../../new_fields/URLField';
+import { ComputedField } from '../../../new_fields/ScriptField';
+import { BoolCast, Cast, FieldValue, NumCast, StrCast } from '../../../new_fields/Types';
+import { AudioField, ImageField } from '../../../new_fields/URLField';
+import { RouteStore } from '../../../server/RouteStore';
 import { Utils } from '../../../Utils';
+import { CognitiveServices, Confidence, Service, Tag } from '../../cognitive_services/CognitiveServices';
+import { Docs } from '../../documents/Documents';
 import { DragManager } from '../../util/DragManager';
+import { CompileScript } from '../../util/Scripting';
 import { undoBatch } from '../../util/UndoManager';
 import { ContextMenu } from "../../views/ContextMenu";
 import { ContextMenuProps } from '../ContextMenuItem';
 import { DocComponent } from '../DocComponent';
 import { InkingControl } from '../InkingControl';
 import { positionSchema } from './DocumentView';
+import FaceRectangles from './FaceRectangles';
 import { FieldView, FieldViewProps } from './FieldView';
 import "./ImageBox.scss";
 import React = require("react");
-import { RouteStore } from '../../../server/RouteStore';
-import { Docs, DocumentType } from '../../documents/Documents';
-import { DocServer } from '../../DocServer';
-import { Font } from '@react-pdf/renderer';
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { CognitiveServices, Service, Tag, Confidence } from '../../cognitive_services/CognitiveServices';
-import FaceRectangles from './FaceRectangles';
-import { faEye } from '@fortawesome/free-regular-svg-icons';
-import { ComputedField } from '../../../new_fields/ScriptField';
-import { CompileScript } from '../../util/Scripting';
-import { thisExpression } from 'babel-types';
 var requestImageSize = require('../../util/request-image-size');
 var path = require('path');
 const { Howl } = require('howler');
 
 
-library.add(faImage, faEye, faPaintBrush);
+library.add(faImage, faEye as any, faPaintBrush);
 library.add(faFileAudio, faAsterisk);
 
 
-- 
cgit v1.2.3-70-g09d2


From e65a75245617e2161ad5a75dd2b91461144dfdf7 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Sat, 3 Aug 2019 18:47:48 -0400
Subject: fixed marquee collection'ing with backgrounds. fixed rotating images.
  fixed marqueeing ink.

---
 src/client/views/InkingCanvas.tsx                  |  2 +-
 .../collections/collectionFreeForm/MarqueeView.tsx | 21 +++++++++++---------
 src/client/views/nodes/FormattedTextBox.tsx        |  8 ++++----
 src/client/views/nodes/ImageBox.tsx                | 10 +++++-----
 src/new_fields/Doc.ts                              | 23 +++++++++++++---------
 5 files changed, 36 insertions(+), 28 deletions(-)

(limited to 'src/client/views/nodes/ImageBox.tsx')

diff --git a/src/client/views/InkingCanvas.tsx b/src/client/views/InkingCanvas.tsx
index c4cd863d1..1c221e3df 100644
--- a/src/client/views/InkingCanvas.tsx
+++ b/src/client/views/InkingCanvas.tsx
@@ -176,7 +176,7 @@ export class InkingCanvas extends React.Component<InkCanvasProps> {
     }
 
     render() {
-        let svgCanvasStyle = InkingControl.Instance.selectedTool !== InkTool.None ? "canSelect" : "noSelect";
+        let svgCanvasStyle = InkingControl.Instance.selectedTool !== InkTool.None && !this.props.Document.isBackground ? "canSelect" : "noSelect";
         return (
             <div className="inkingCanvas">
                 <div className={`inkingCanvas-${svgCanvasStyle}`} onPointerDown={this.onPointerDown} />
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index ff96bd993..aad26efa0 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -226,15 +226,17 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
     }
 
     get ink() {
-        let container = this.props.container.Document;
+        let container = this.props.container.props.Document;
         let containerKey = this.props.container.props.fieldKey;
-        return Cast(container[containerKey + "_ink"], InkField);
+        let extensionDoc = Doc.resolvedFieldDataDoc(container, containerKey, "true");
+        return Cast(extensionDoc.ink, InkField);
     }
 
     set ink(value: InkField | undefined) {
-        let container = Doc.GetProto(this.props.container.Document);
+        let container = Doc.GetProto(this.props.container.props.Document);
         let containerKey = this.props.container.props.fieldKey;
-        container[containerKey + "_ink"] = value;
+        let extensionDoc = Doc.resolvedFieldDataDoc(container, containerKey, "true");
+        extensionDoc.ink = value;
     }
 
     @undoBatch
@@ -247,7 +249,7 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
             this._commandExecuted = true;
             e.stopPropagation();
             (e as any).propagationIsStopped = true;
-            this.marqueeSelect().map(d => this.props.removeDocument(d));
+            this.marqueeSelect(false).map(d => this.props.removeDocument(d));
             if (this.ink) {
                 this.marqueeInkDelete(this.ink.inkData);
             }
@@ -261,7 +263,7 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
             e.preventDefault();
             (e as any).propagationIsStopped = true;
             let bounds = this.Bounds;
-            let selected = this.marqueeSelect();
+            let selected = this.marqueeSelect(false);
             if (e.key === "c") {
                 selected.map(d => {
                     this.props.removeDocument(d);
@@ -283,7 +285,8 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
                 height: bounds.height,
                 title: e.key === "s" || e.key === "S" ? "-summary-" : "a nested collection",
             });
-            newCollection.data_ink = inkData ? new InkField(this.marqueeInkSelect(inkData)) : undefined;
+            let dataExtensionField = Doc.CreateDocumentExtensionForField(newCollection, "data");
+            dataExtensionField.ink = inkData ? new InkField(this.marqueeInkSelect(inkData)) : undefined;
             this.marqueeInkDelete(inkData);
 
             if (e.key === "s") {
@@ -367,7 +370,7 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
         }
     }
 
-    marqueeSelect() {
+    marqueeSelect(selectBackgrounds: boolean = true) {
         let selRect = this.Bounds;
         let selection: Doc[] = [];
         this.props.activeDocuments().filter(doc => !doc.isBackground).map(doc => {
@@ -379,7 +382,7 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
                 selection.push(doc);
             }
         });
-        if (!selection.length) {
+        if (!selection.length && selectBackgrounds) {
             this.props.activeDocuments().map(doc => {
                 var x = NumCast(doc.x);
                 var y = NumCast(doc.y);
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index e076efe18..6c97add76 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -674,7 +674,8 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
         let self = this;
         let style = this.props.isOverlay ? "scroll" : "hidden";
         let rounded = StrCast(this.props.Document.borderRounding) === "100%" ? "-rounded" : "";
-        let interactive = InkingControl.Instance.selectedTool ? "" : "interactive";
+        let interactive: "all" | "none" = InkingControl.Instance.selectedTool || this.props.Document.isBackground ||
+            (this.props.Document.isButton && !this.props.isSelected()) ? "none" : "all";
         Doc.UpdateDocumentExtensionForField(this.dataDoc, this.props.fieldKey);
         return (
             <div className={`formattedTextBox-cont-${style}`} ref={this._ref}
@@ -683,7 +684,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
                     background: this.props.hideOnLeave ? "rgba(0,0,0,0.4)" : undefined,
                     opacity: this.props.hideOnLeave ? (this._entered || this.props.isSelected() || this.props.Document.libraryBrush ? 1 : 0.1) : 1,
                     color: this.props.color ? this.props.color : this.props.hideOnLeave ? "white" : "inherit",
-                    pointerEvents: interactive ? "all" : "none",
+                    pointerEvents: interactive,
                     fontSize: "13px"
                 }}
                 onKeyDown={this.onKeyPress}
@@ -694,12 +695,11 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
                 onPointerUp={this.onPointerUp}
                 onPointerDown={this.onPointerDown}
                 onMouseDown={this.onMouseDown}
-                // tfs: do we need this event handler
                 onWheel={this.onPointerWheel}
                 onPointerEnter={this.onPointerEnter}
                 onPointerLeave={this.onPointerLeave}
             >
-                <div className={`formattedTextBox-inner${rounded}`} ref={this.createDropTarget} style={{ whiteSpace: "pre-wrap", pointerEvents: this.props.Document.isButton && !this.props.isSelected() ? "none" : "all" }} />
+                <div className={`formattedTextBox-inner${rounded}`} ref={this.createDropTarget} style={{ whiteSpace: "pre-wrap" }} />
             </div>
         );
     }
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 17dc4184a..0d9c2bb8a 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -314,14 +314,14 @@ export class ImageBox extends DocComponent<FieldViewProps, ImageDocument>(ImageD
     resize(srcpath: string, layoutdoc: Doc) {
         requestImageSize(srcpath)
             .then((size: any) => {
-                let aspect = size.height / size.width;
                 let rotation = NumCast(this.dataDoc.rotation) % 180;
-                if (rotation === 90 || rotation === 270) aspect = 1 / aspect;
-                if (Math.abs(NumCast(layoutdoc.height) - size.height) > 1 || Math.abs(NumCast(layoutdoc.width) - size.width) > 1) {
+                let realsize = rotation === 90 || rotation === 270 ? { height: size.width, width: size.height } : size;
+                let aspect = realsize.height / realsize.width;
+                if (Math.abs(NumCast(layoutdoc.height) - realsize.height) > 1 || Math.abs(NumCast(layoutdoc.width) - realsize.width) > 1) {
                     setTimeout(action(() => {
                         layoutdoc.height = layoutdoc[WidthSym]() * aspect;
-                        layoutdoc.nativeHeight = size.height;
-                        layoutdoc.nativeWidth = size.width;
+                        layoutdoc.nativeHeight = realsize.height;
+                        layoutdoc.nativeWidth = realsize.width;
                     }), 0);
                 }
             })
diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts
index b70951040..b081588a3 100644
--- a/src/new_fields/Doc.ts
+++ b/src/new_fields/Doc.ts
@@ -341,19 +341,24 @@ export namespace Doc {
         return fieldExt && doc[fieldKey + "_ext"] instanceof Doc ? doc[fieldKey + "_ext"] as Doc : doc;
     }
 
+    export function CreateDocumentExtensionForField(doc: Doc, fieldKey: string) {
+        let docExtensionForField = new Doc(doc[Id] + fieldKey, true);
+        docExtensionForField.title = fieldKey + ".ext";
+        docExtensionForField.extendsDoc = doc; // this is used by search to map field matches on the extension doc back to the document it extends.
+        docExtensionForField.type = DocumentType.EXTENSION;
+        let proto: Doc | undefined = doc;
+        while (proto && !Doc.IsPrototype(proto)) {
+            proto = proto.proto;
+        }
+        (proto ? proto : doc)[fieldKey + "_ext"] = new PrefetchProxy(docExtensionForField);
+        return docExtensionForField;
+    }
+
     export function UpdateDocumentExtensionForField(doc: Doc, fieldKey: string) {
         let docExtensionForField = doc[fieldKey + "_ext"] as Doc;
         if (docExtensionForField === undefined) {
             setTimeout(() => {
-                docExtensionForField = new Doc(doc[Id] + fieldKey, true);
-                docExtensionForField.title = fieldKey + ".ext";
-                docExtensionForField.extendsDoc = doc; // this is used by search to map field matches on the extension doc back to the document it extends.
-                docExtensionForField.type = DocumentType.EXTENSION;
-                let proto: Doc | undefined = doc;
-                while (proto && !Doc.IsPrototype(proto)) {
-                    proto = proto.proto;
-                }
-                (proto ? proto : doc)[fieldKey + "_ext"] = new PrefetchProxy(docExtensionForField);
+                CreateDocumentExtensionForField(doc, field);
             }, 0);
         } else if (doc instanceof Doc) { // backward compatibility -- add fields for docs that don't have them already
             docExtensionForField.extendsDoc === undefined && setTimeout(() => docExtensionForField.extendsDoc = doc, 0);
-- 
cgit v1.2.3-70-g09d2

