From 36eed6cc3a3387a1f7755a848aea4e19e2645e14 Mon Sep 17 00:00:00 2001
From: Stanley Yip <stanley_yip@brown.edu>
Date: Thu, 9 Jan 2020 19:55:52 -0500
Subject: some stuff that ive played around with today. mobile interface, five
 fingers, other stuff

---
 src/client/views/InkingControl.tsx | 21 ++++++++++++---------
 1 file changed, 12 insertions(+), 9 deletions(-)

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

diff --git a/src/client/views/InkingControl.tsx b/src/client/views/InkingControl.tsx
index e33f193b8..243123352 100644
--- a/src/client/views/InkingControl.tsx
+++ b/src/client/views/InkingControl.tsx
@@ -4,19 +4,18 @@ import { Doc } from "../../new_fields/Doc";
 import { InkTool } from "../../new_fields/InkField";
 import { List } from "../../new_fields/List";
 import { listSpec } from "../../new_fields/Schema";
-import { Cast, NumCast, StrCast } from "../../new_fields/Types";
+import { Cast, NumCast, StrCast, FieldValue } from "../../new_fields/Types";
 import { Utils } from "../../Utils";
 import { Scripting } from "../util/Scripting";
 import { SelectionManager } from "../util/SelectionManager";
 import { undoBatch, UndoManager } from "../util/UndoManager";
 import { CurrentUserUtils } from "../../server/authentication/models/current_user_utils";
 
-
 export class InkingControl {
     @observable static Instance: InkingControl;
-    @observable private _selectedTool: InkTool = InkTool.None;
-    @observable private _selectedColor: string = "rgb(244, 67, 54)";
-    @observable private _selectedWidth: string = "5";
+    @computed private get _selectedTool(): InkTool { return FieldValue(NumCast(CurrentUserUtils.UserDocument.inkTool)) ?? InkTool.None; }
+    @computed private get _selectedColor(): string { return FieldValue(StrCast(CurrentUserUtils.UserDocument.inkColor)) ?? "rgb(244, 67, 54)"; }
+    @computed private get _selectedWidth(): string { return FieldValue(StrCast(CurrentUserUtils.UserDocument.inkWidth)) ?? "5"; }
     @observable public _open: boolean = false;
 
     constructor() {
@@ -24,7 +23,8 @@ export class InkingControl {
     }
 
     switchTool = action((tool: InkTool): void => {
-        this._selectedTool = tool;
+        // this._selectedTool = tool;
+        CurrentUserUtils.UserDocument.inkTool = tool;
     });
     decimalToHexString(number: number) {
         if (number < 0) {
@@ -36,7 +36,7 @@ export class InkingControl {
 
     @undoBatch
     switchColor = action((color: ColorState): void => {
-        this._selectedColor = color.hex + (color.rgb.a !== undefined ? this.decimalToHexString(Math.round(color.rgb.a * 255)) : "ff");
+        CurrentUserUtils.UserDocument.inkColor = color.hex + (color.rgb.a !== undefined ? this.decimalToHexString(Math.round(color.rgb.a * 255)) : "ff");
 
         if (InkingControl.Instance.selectedTool === InkTool.None) {
             const selected = SelectionManager.SelectedDocuments();
@@ -99,7 +99,8 @@ export class InkingControl {
     });
     @action
     switchWidth = (width: string): void => {
-        this._selectedWidth = width;
+        // this._selectedWidth = width;
+        CurrentUserUtils.UserDocument.inkWidth = width;
     }
 
     @computed
@@ -114,7 +115,8 @@ export class InkingControl {
 
     @action
     updateSelectedColor(value: string) {
-        this._selectedColor = value;
+        // this._selectedColor = value;
+        CurrentUserUtils.UserDocument.inkColor = value;
     }
 
     @computed
@@ -127,6 +129,7 @@ Scripting.addGlobal(function activatePen(pen: any, width: any, color: any) { Ink
 Scripting.addGlobal(function activateBrush(pen: any, width: any, color: any) { InkingControl.Instance.switchTool(pen ? InkTool.Highlighter : InkTool.None); InkingControl.Instance.switchWidth(width); InkingControl.Instance.updateSelectedColor(color); });
 Scripting.addGlobal(function activateEraser(pen: any) { return InkingControl.Instance.switchTool(pen ? InkTool.Eraser : InkTool.None); });
 Scripting.addGlobal(function activateScrubber(pen: any) { return InkingControl.Instance.switchTool(pen ? InkTool.Scrubber : InkTool.None); });
+Scripting.addGlobal(function activateStamp(pen: any) { return InkingControl.Instance.switchTool(pen ? InkTool.Stamp : InkTool.None); });
 Scripting.addGlobal(function deactivateInk() { return InkingControl.Instance.switchTool(InkTool.None); });
 Scripting.addGlobal(function setInkWidth(width: any) { return InkingControl.Instance.switchWidth(width); });
 Scripting.addGlobal(function setInkColor(color: any) { return InkingControl.Instance.updateSelectedColor(color); });
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2


From d86b4db095379d473820271868e8f7cd5830d502 Mon Sep 17 00:00:00 2001
From: Stanley Yip <stanley_yip@brown.edu>
Date: Mon, 13 Jan 2020 15:25:07 -0500
Subject: palette events are now on gestureOverlay, but cffv and dv is still
 capturing one and two finger events, which makes it impossible for the
 gestureoverlay to capture 5 fingers spread across different targets

---
 src/client/documents/Documents.ts                  |  3 +
 src/client/util/InteractionUtils.ts                | 10 ++-
 src/client/views/GestureOverlay.tsx                | 64 ++++++++++++++-
 src/client/views/InkingControl.tsx                 |  5 +-
 src/client/views/Palette.scss                      | 10 ++-
 src/client/views/Palette.tsx                       | 44 +++++++++-
 src/client/views/Touchable.tsx                     | 21 +++--
 .../collectionFreeForm/CollectionFreeFormView.tsx  | 94 +++++++++++-----------
 src/client/views/nodes/DocumentView.tsx            | 24 +++++-
 src/new_fields/documentSchemas.ts                  |  2 +
 .../authentication/models/current_user_utils.ts    | 23 ++++++
 11 files changed, 224 insertions(+), 76 deletions(-)

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 1853be529..64abd4f57 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -103,6 +103,8 @@ export interface DocumentOptions {
     ischecked?: ScriptField; // returns whether a font icon box is checked
     activePen?: Doc; // which pen document is currently active (used as the radio button state for the 'unhecked' pen tool scripts)
     onClick?: ScriptField;
+    onPointerDown?: ScriptField;
+    onPointerUp?: ScriptField;
     dragFactory?: Doc; // document to create when dragging with a suitable onDragStart script
     onDragStart?: ScriptField; //script to execute at start of drag operation --  e.g., when a "creator" button is dragged this script generates a different document to drop
     icon?: string;
@@ -116,6 +118,7 @@ export interface DocumentOptions {
     color?: string;
     limitHeight?: number; // maximum height for newly created (eg, from pasting) text documents
     // [key: string]: Opt<Field>;
+    pointerHack?: boolean; // for buttons, allows onClick handler to fire onPointerDown
 }
 
 class EmptyBox {
diff --git a/src/client/util/InteractionUtils.ts b/src/client/util/InteractionUtils.ts
index 2e4e8c7ca..76b43da3c 100644
--- a/src/client/util/InteractionUtils.ts
+++ b/src/client/util/InteractionUtils.ts
@@ -8,12 +8,14 @@ export namespace InteractionUtils {
     const REACT_POINTER_PEN_BUTTON = 0;
     const ERASER_BUTTON = 5;
 
-    export function GetMyTargetTouches(e: TouchEvent | React.TouchEvent, prevPoints: Map<number, React.Touch>): React.Touch[] {
+    export function GetMyTargetTouches(e: TouchEvent | React.TouchEvent, prevPoints: Map<number, React.Touch>, ignorePen: boolean): React.Touch[] {
         const myTouches = new Array<React.Touch>();
         for (let i = 0; i < e.targetTouches.length; i++) {
-            const pt = e.targetTouches.item(i);
+            const pt: any = e.targetTouches.item(i);
             if (pt && prevPoints.has(pt.identifier)) {
-                myTouches.push(pt);
+                if (ignorePen || (pt.radiusX > 1 && pt.radiusY > 1)) {
+                    myTouches.push(pt);
+                }
             }
         }
         return myTouches;
@@ -23,7 +25,7 @@ export namespace InteractionUtils {
         switch (type) {
             // pen and eraser are both pointer type 'pen', but pen is button 0 and eraser is button 5. -syip2
             case PENTYPE:
-                return e.pointerType === PENTYPE && e.button === (e instanceof PointerEvent ? POINTER_PEN_BUTTON : REACT_POINTER_PEN_BUTTON);
+                return e.pointerType === PENTYPE && (e.button === -1 || e.button === 0);
             case ERASERTYPE:
                 return e.pointerType === PENTYPE && e.button === (e instanceof PointerEvent ? ERASER_BUTTON : ERASER_BUTTON);
             default:
diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index 848927912..830c06f1f 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -2,7 +2,7 @@ import React = require("react");
 import { Touchable } from "./Touchable";
 import { observer } from "mobx-react";
 import "./GestureOverlay.scss"
-import { computed, observable, action } from "mobx";
+import { computed, observable, action, runInAction } from "mobx";
 import { CreatePolyline } from "./InkingStroke";
 import { GestureUtils } from "../../pen-gestures/GestureUtils";
 import { InteractionUtils } from "../util/InteractionUtils";
@@ -12,14 +12,22 @@ import { Doc } from "../../new_fields/Doc";
 import { LinkManager } from "../util/LinkManager";
 import { DocUtils } from "../documents/Documents";
 import { undoBatch } from "../util/UndoManager";
+import { Scripting } from "../util/Scripting";
+import { FieldValue, Cast } from "../../new_fields/Types";
+import { CurrentUserUtils } from "../../server/authentication/models/current_user_utils";
+import Palette from "./Palette";
 
 @observer
 export default class GestureOverlay extends Touchable {
     static Instance: GestureOverlay;
 
     @observable private _points: { X: number, Y: number }[] = [];
+    @observable private _palette?: JSX.Element;
+    @observable public Color: string = "rgb(244, 67, 54)";
+    @observable public Width: number = 5;
 
     private _d1: Doc | undefined;
+    private thumbIdentifier?: number;
 
     constructor(props: Readonly<{}>) {
         super(props);
@@ -27,6 +35,47 @@ export default class GestureOverlay extends Touchable {
         GestureOverlay.Instance = this;
     }
 
+    @action
+    handleHandDown = (e: React.TouchEvent) => {
+        const fingers = InteractionUtils.GetMyTargetTouches(e, this.prevPoints, true);
+        const thumb = fingers.reduce((a, v) => a.clientY > v.clientY ? a : v, fingers[0]);
+        this.thumbIdentifier = thumb?.identifier;
+        const others = fingers.filter(f => f !== thumb);
+        const minX = Math.min(...others.map(f => f.clientX));
+        const minY = Math.min(...others.map(f => f.clientY));
+        // const t = this.getTransform().transformPoint(minX, minY);
+        // const th = this.getTransform().transformPoint(thumb.clientX, thumb.clientY);
+
+        const thumbDoc = FieldValue(Cast(CurrentUserUtils.setupThumbDoc(CurrentUserUtils.UserDocument), Doc));
+        if (thumbDoc) {
+            this._palette = <Palette x={minX} y={minY} thumb={[thumb.clientX, thumb.clientY]} thumbDoc={thumbDoc} />;
+        }
+
+        document.removeEventListener("touchmove", this.onTouch);
+        document.removeEventListener("touchmove", this.handleHandMove);
+        document.addEventListener("touchmove", this.handleHandMove);
+        document.removeEventListener("touchend", this.handleHandUp);
+        document.addEventListener("touchend", this.handleHandUp);
+    }
+
+    @action
+    handleHandMove = (e: TouchEvent) => {
+        for (let i = 0; i < e.changedTouches.length; i++) {
+            const pt = e.changedTouches.item(i);
+            if (pt?.identifier === this.thumbIdentifier) {
+            }
+        }
+    }
+
+    @action
+    handleHandUp = (e: TouchEvent) => {
+        this.onTouchEnd(e);
+        if (this.prevPoints.size < 3) {
+            this._palette = undefined;
+            document.removeEventListener("touchend", this.handleHandUp);
+        }
+    }
+
     @action
     onPointerDown = (e: React.PointerEvent) => {
         if (InteractionUtils.IsType(e, InteractionUtils.PENTYPE) || (InkingControl.Instance.selectedTool === InkTool.Highlighter || InkingControl.Instance.selectedTool === InkTool.Pen)) {
@@ -82,6 +131,8 @@ export default class GestureOverlay extends Touchable {
         return actionPerformed;
     }
 
+
+
     @action
     onPointerUp = (e: PointerEvent) => {
         if (this._points.length > 1) {
@@ -157,16 +208,21 @@ export default class GestureOverlay extends Touchable {
 
         return (
             <svg width={B.width} height={B.height} style={{ transform: `translate(${B.left}px, ${B.top}px)`, pointerEvents: "none", position: "absolute", zIndex: 30000 }}>
-                {CreatePolyline(this._points, B.left, B.top)}
+                {CreatePolyline(this._points, B.left, B.top, this.Color, this.Width)}
             </svg>
         );
     }
 
     render() {
         return (
-            <div className="gestureOverlay-cont" onPointerDown={this.onPointerDown}>
+            <div className="gestureOverlay-cont" onPointerDown={this.onPointerDown} onTouchStart={this.onTouchStart}>
                 {this.props.children}
+                {this._palette}
                 {this.currentStroke}
             </div>);
     }
-}
\ No newline at end of file
+}
+
+Scripting.addGlobal("GestureOverlay", GestureOverlay);
+Scripting.addGlobal(function setPen(width: any, color: any) { runInAction(() => { GestureOverlay.Instance.Color = color; GestureOverlay.Instance.Width = width; }); });
+Scripting.addGlobal(function resetPen() { runInAction(() => { GestureOverlay.Instance.Color = "rgb(244, 67, 54)"; GestureOverlay.Instance.Width = 5; }); });
\ No newline at end of file
diff --git a/src/client/views/InkingControl.tsx b/src/client/views/InkingControl.tsx
index 243123352..be07a9024 100644
--- a/src/client/views/InkingControl.tsx
+++ b/src/client/views/InkingControl.tsx
@@ -10,12 +10,13 @@ import { Scripting } from "../util/Scripting";
 import { SelectionManager } from "../util/SelectionManager";
 import { undoBatch, UndoManager } from "../util/UndoManager";
 import { CurrentUserUtils } from "../../server/authentication/models/current_user_utils";
+import GestureOverlay from "./GestureOverlay";
 
 export class InkingControl {
     @observable static Instance: InkingControl;
     @computed private get _selectedTool(): InkTool { return FieldValue(NumCast(CurrentUserUtils.UserDocument.inkTool)) ?? InkTool.None; }
-    @computed private get _selectedColor(): string { return FieldValue(StrCast(CurrentUserUtils.UserDocument.inkColor)) ?? "rgb(244, 67, 54)"; }
-    @computed private get _selectedWidth(): string { return FieldValue(StrCast(CurrentUserUtils.UserDocument.inkWidth)) ?? "5"; }
+    @computed private get _selectedColor(): string { return GestureOverlay.Instance.Color ?? FieldValue(StrCast(CurrentUserUtils.UserDocument.inkColor)) ?? "rgb(244, 67, 54)"; }
+    @computed private get _selectedWidth(): string { return GestureOverlay.Instance.Width?.toString() ?? FieldValue(StrCast(CurrentUserUtils.UserDocument.inkWidth)) ?? "5"; }
     @observable public _open: boolean = false;
 
     constructor() {
diff --git a/src/client/views/Palette.scss b/src/client/views/Palette.scss
index 60004c81f..2626774cb 100644
--- a/src/client/views/Palette.scss
+++ b/src/client/views/Palette.scss
@@ -4,15 +4,17 @@
         height: 300px;
         touch-action: pan-x;
         overflow: scroll;
+        position: absolute;
 
         .palette-thumbContent {
             width: 100%;
             height: 100%;
+        }
 
-            .palette-button {
-                width: 100px;
-                height: 100px;
-            }
+        .palette-button {
+            width: 100px;
+            height: 100px;
+            background: blue;
         }
     }
 }
\ No newline at end of file
diff --git a/src/client/views/Palette.tsx b/src/client/views/Palette.tsx
index 390b7e2c2..3649cccfe 100644
--- a/src/client/views/Palette.tsx
+++ b/src/client/views/Palette.tsx
@@ -1,22 +1,60 @@
 import * as React from "react";
 import "./Palette.scss";
 import { PointData } from "../../new_fields/InkField";
+import { Doc } from "../../new_fields/Doc";
+import { Docs } from "../documents/Documents";
+import { ScriptField, ComputedField } from "../../new_fields/ScriptField";
+import { List } from "../../new_fields/List";
+import { DocumentView } from "./nodes/DocumentView";
+import { emptyPath, returnFalse, emptyFunction, returnOne, returnEmptyString, returnTrue } from "../../Utils";
+import { CurrentUserUtils } from "../../server/authentication/models/current_user_utils";
+import { Transform } from "../util/Transform";
+import { computed, action } from "mobx";
+import { FieldValue, Cast } from "../../new_fields/Types";
+import { observer } from "mobx-react";
+import { DocumentContentsView } from "./nodes/DocumentContentsView";
+import { CollectionStackingView } from "./collections/CollectionStackingView";
+import { CollectionView } from "./collections/CollectionView";
 
 export interface PaletteProps {
     x: number;
     y: number;
     thumb: number[];
+    thumbDoc: Doc;
 }
 
+@observer
 export default class Palette extends React.Component<PaletteProps> {
     render() {
         return (
             <div className="palette-container" style={{ transform: `translate(${this.props.x}px, ${this.props.y}px)` }}>
                 <div className="palette-thumb" style={{ transform: `translate(${this.props.thumb[0] - this.props.x}px, ${this.props.thumb[1] - this.props.y}px)` }}>
                     <div className="palette-thumbContent">
-                        <div className="palette-button" style={{ background: "green" }} onPointerDown={() => console.log("hi")}>1</div>
-                        <div className="palette-button" style={{ background: "red" }}>2</div>
-                        <div className="palette-button" style={{ background: "blue" }}>3</div>
+                        <DocumentView
+                            Document={this.props.thumbDoc}
+                            DataDoc={undefined}
+                            LibraryPath={emptyPath}
+                            addDocument={undefined}
+                            addDocTab={returnFalse}
+                            pinToPres={emptyFunction}
+                            removeDocument={undefined}
+                            ruleProvider={undefined}
+                            onClick={undefined}
+                            ScreenToLocalTransform={Transform.Identity}
+                            ContentScaling={returnOne}
+                            PanelWidth={() => window.screen.width}
+                            PanelHeight={() => window.screen.height}
+                            renderDepth={0}
+                            focus={emptyFunction}
+                            backgroundColor={returnEmptyString}
+                            parentActive={returnTrue}
+                            whenActiveChanged={emptyFunction}
+                            bringToFront={emptyFunction}
+                            ContainingCollectionView={undefined}
+                            ContainingCollectionDoc={undefined}
+                            zoomToScale={emptyFunction}
+                            getScale={returnOne}>
+                        </DocumentView>
                     </div>
                 </div>
             </div>
diff --git a/src/client/views/Touchable.tsx b/src/client/views/Touchable.tsx
index 3eb66ff72..24ea801a0 100644
--- a/src/client/views/Touchable.tsx
+++ b/src/client/views/Touchable.tsx
@@ -21,15 +21,26 @@ export abstract class Touchable<T = {}> extends React.Component<T> {
      */
     @action
     protected onTouchStart = (e: React.TouchEvent): void => {
+        const actualPts: React.Touch[] = [];
         for (let i = 0; i < e.targetTouches.length; i++) {
             const pt: any = e.targetTouches.item(i);
+            actualPts.push(pt);
             // pen is also a touch, but with a radius of 0.5 (at least with the surface pens)
             // and this seems to be the only way of differentiating pen and touch on touch events
-            if (pt.radiusX > 0.5 && pt.radiusY > 0.5) {
+            if (pt.radiusX > 1 && pt.radiusY > 1) {
                 this.prevPoints.set(pt.identifier, pt);
             }
         }
 
+        const ptsToDelete: number[] = [];
+        this.prevPoints.forEach(pt => {
+            if (!actualPts.includes(pt)) {
+                ptsToDelete.push(pt.identifier);
+            }
+        });
+
+        ptsToDelete.forEach(pt => this.prevPoints.delete(pt));
+
         if (this.prevPoints.size) {
             switch (this.prevPoints.size) {
                 case 1:
@@ -57,13 +68,12 @@ export abstract class Touchable<T = {}> extends React.Component<T> {
     */
     @action
     protected onTouch = (e: TouchEvent): void => {
-        const myTouches = InteractionUtils.GetMyTargetTouches(e, this.prevPoints);
+        const myTouches = InteractionUtils.GetMyTargetTouches(e, this.prevPoints, true);
 
         // if we're not actually moving a lot, don't consider it as dragging yet
         if (!InteractionUtils.IsDragging(this.prevPoints, myTouches, 5) && !this._touchDrag) return;
         this._touchDrag = true;
         if (this.holdTimer) {
-            console.log("clear");
             clearTimeout(this.holdTimer);
             this.holdTimer = undefined;
         }
@@ -99,7 +109,6 @@ export abstract class Touchable<T = {}> extends React.Component<T> {
             }
         }
         if (this.holdTimer) {
-            console.log("clear");
             clearTimeout(this.holdTimer);
             this.holdTimer = undefined;
         }
@@ -152,7 +161,7 @@ export abstract class Touchable<T = {}> extends React.Component<T> {
     }
 
     handleHandDown = (e: React.TouchEvent) => {
-        e.stopPropagation();
-        e.preventDefault();
+        // e.stopPropagation();
+        // e.preventDefault();
     }
 }
\ No newline at end of file
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index d7cccc036..84945c6e6 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -9,7 +9,7 @@ import { Id } from "../../../../new_fields/FieldSymbols";
 import { InkTool, InkField, InkData } from "../../../../new_fields/InkField";
 import { createSchema, makeInterface } from "../../../../new_fields/Schema";
 import { ScriptField } from "../../../../new_fields/ScriptField";
-import { BoolCast, Cast, DateCast, NumCast, StrCast } from "../../../../new_fields/Types";
+import { BoolCast, Cast, DateCast, NumCast, StrCast, FieldValue } from "../../../../new_fields/Types";
 import { CurrentUserUtils } from "../../../../server/authentication/models/current_user_utils";
 import { aggregateBounds, emptyFunction, intersectRect, returnOne, Utils } from "../../../../Utils";
 import { DocServer } from "../../../DocServer";
@@ -468,7 +468,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
     handle1PointerMove = (e: TouchEvent) => {
         // panning a workspace
         if (!e.cancelBubble) {
-            const myTouches = InteractionUtils.GetMyTargetTouches(e, this.prevPoints);
+            const myTouches = InteractionUtils.GetMyTargetTouches(e, this.prevPoints, true);
             const pt = myTouches[0];
             if (pt) {
                 if (InkingControl.Instance.selectedTool === InkTool.None) {
@@ -490,7 +490,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
     handle2PointersMove = (e: TouchEvent) => {
         // pinch zooming
         if (!e.cancelBubble) {
-            const myTouches = InteractionUtils.GetMyTargetTouches(e, this.prevPoints);
+            const myTouches = InteractionUtils.GetMyTargetTouches(e, this.prevPoints, true);
             const pt1 = myTouches[0];
             const pt2 = myTouches[1];
 
@@ -849,51 +849,47 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
     }
 
     private thumbIdentifier?: number;
-    private hand?: React.Touch[];
 
-    @action
-    handleHandDown = (e: React.TouchEvent) => {
-        const fingers = InteractionUtils.GetMyTargetTouches(e, this.prevPoints);
-        this.hand = fingers;
-        const thumb = fingers.reduce((a, v) => a.clientY > v.clientY ? a : v, fingers[0]);
-        this.thumbIdentifier = thumb?.identifier;
-        const others = fingers.filter(f => f !== thumb);
-        const minX = Math.min(...others.map(f => f.clientX));
-        const minY = Math.min(...others.map(f => f.clientY));
-        const t = this.getTransform().transformPoint(minX, minY);
-        const th = this.getTransform().transformPoint(thumb.clientX, thumb.clientY);
-        this._palette = <Palette x={t[0]} y={t[1]} thumb={th} />;
-
-        document.removeEventListener("touchmove", this.onTouch);
-        document.removeEventListener("touchmove", this.handleHandMove);
-        document.addEventListener("touchmove", this.handleHandMove);
-        document.removeEventListener("touchend", this.handleHandUp);
-        document.addEventListener("touchend", this.handleHandUp);
-    }
-
-    @action
-    handleHandMove = (e: TouchEvent) => {
-        for (let i = 0; i < e.changedTouches.length; i++) {
-            const pt = e.changedTouches.item(i);
-            if (pt?.identifier === this.thumbIdentifier) {
-            }
-        }
-    }
-
-    @action
-    handleHandUp = (e: TouchEvent) => {
-        console.log(e.changedTouches.length);
-        this.onTouchEnd(e);
-        if (this.prevPoints.size < 3) {
-            if (this.hand) {
-                for (const h of this.hand) {
-                    this.prevPoints.has(h.identifier) && this.prevPoints.delete(h.identifier);
-                }
-            }
-            this._palette = undefined;
-            document.removeEventListener("touchend", this.handleHandUp);
-        }
-    }
+    // @action
+    // handleHandDown = (e: React.TouchEvent) => {
+    //     const fingers = InteractionUtils.GetMyTargetTouches(e, this.prevPoints, true);
+    //     const thumb = fingers.reduce((a, v) => a.clientY > v.clientY ? a : v, fingers[0]);
+    //     this.thumbIdentifier = thumb?.identifier;
+    //     const others = fingers.filter(f => f !== thumb);
+    //     const minX = Math.min(...others.map(f => f.clientX));
+    //     const minY = Math.min(...others.map(f => f.clientY));
+    //     const t = this.getTransform().transformPoint(minX, minY);
+    //     const th = this.getTransform().transformPoint(thumb.clientX, thumb.clientY);
+
+    //     const thumbDoc = FieldValue(Cast(CurrentUserUtils.setupThumbDoc(CurrentUserUtils.UserDocument), Doc));
+    //     if (thumbDoc) {
+    //         this._palette = <Palette x={t[0]} y={t[1]} thumb={th} thumbDoc={thumbDoc} />;
+    //     }
+
+    //     document.removeEventListener("touchmove", this.onTouch);
+    //     document.removeEventListener("touchmove", this.handleHandMove);
+    //     document.addEventListener("touchmove", this.handleHandMove);
+    //     document.removeEventListener("touchend", this.handleHandUp);
+    //     document.addEventListener("touchend", this.handleHandUp);
+    // }
+
+    // @action
+    // handleHandMove = (e: TouchEvent) => {
+    //     for (let i = 0; i < e.changedTouches.length; i++) {
+    //         const pt = e.changedTouches.item(i);
+    //         if (pt?.identifier === this.thumbIdentifier) {
+    //         }
+    //     }
+    // }
+
+    // @action
+    // handleHandUp = (e: TouchEvent) => {
+    //     this.onTouchEnd(e);
+    //     if (this.prevPoints.size < 3) {
+    //         this._palette = undefined;
+    //         document.removeEventListener("touchend", this.handleHandUp);
+    //     }
+    // }
 
     onContextMenu = (e: React.MouseEvent) => {
         const layoutItems: ContextMenuProps[] = [];
@@ -958,12 +954,12 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
         ];
     }
 
-    @observable private _palette?: JSX.Element;
+    // @observable private _palette?: JSX.Element;
 
     children = () => {
         const eles: JSX.Element[] = [];
         this.extensionDoc && (eles.push(...this.childViews()));
-        this._palette && (eles.push(this._palette));
+        // this._palette && (eles.push(this._palette));
         // this.currentStroke && (eles.push(this.currentStroke));
         eles.push(<CollectionFreeFormRemoteCursors {...this.props} key="remoteCursors" />);
         return eles;
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 415d0e2ef..bdec94eb3 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -59,6 +59,8 @@ export interface DocumentViewProps {
     LibraryPath: Doc[];
     fitToBox?: boolean;
     onClick?: ScriptField;
+    onPointerDown?: ScriptField;
+    onPointerUp?: ScriptField;
     dragDivName?: string;
     addDocument?: (doc: Doc) => boolean;
     removeDocument?: (doc: Doc) => boolean;
@@ -105,6 +107,8 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     @computed get nativeWidth() { return this.layoutDoc.nativeWidth || 0; }
     @computed get nativeHeight() { return this.layoutDoc.nativeHeight || 0; }
     @computed get onClickHandler() { return this.props.onClick ? this.props.onClick : this.Document.onClick; }
+    @computed get onPointerDownHandler() { return this.props.onPointerDown ? this.props.onPointerDown : this.Document.onPointerDown; }
+    @computed get onPointerUpHandler() { return this.props.onPointerUp ? this.props.onPointerUp : this.Document.onPointerUp; }
 
     @action
     componentDidMount() {
@@ -180,7 +184,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         }
     }
 
-    onClick = async (e: React.MouseEvent) => {
+    onClick = async (e: React.MouseEvent | React.PointerEvent) => {
         if (!e.nativeEvent.cancelBubble && !this.Document.ignoreClick && CurrentUserUtils.MainDocId !== this.props.Document[Id] &&
             (Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD && Math.abs(e.clientY - this._downY) < Utils.DRAG_THRESHOLD)) {
             e.stopPropagation();
@@ -240,8 +244,9 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     }
 
     handle1PointerDown = (e: React.TouchEvent) => {
+        if (this.Document.onPointerDown) return;
         if (!e.nativeEvent.cancelBubble) {
-            const touch = InteractionUtils.GetMyTargetTouches(e, this.prevPoints)[0];
+            const touch = InteractionUtils.GetMyTargetTouches(e, this.prevPoints, true)[0];
             this._downX = touch.clientX;
             this._downY = touch.clientY;
             this._hitTemplateDrag = false;
@@ -265,7 +270,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
             document.removeEventListener("touchmove", this.onTouch);
         }
         else if (!e.cancelBubble && (SelectionManager.IsSelected(this, true) || this.props.parentActive(true) || this.Document.onDragStart || this.Document.onClick) && !this.Document.lockedPosition && !this.Document.inOverlay) {
-            const touch = InteractionUtils.GetMyTargetTouches(e, this.prevPoints)[0];
+            const touch = InteractionUtils.GetMyTargetTouches(e, this.prevPoints, true)[0];
             if (Math.abs(this._downX - touch.clientX) > 3 || Math.abs(this._downY - touch.clientY) > 3) {
                 if (!e.altKey && (!this.topMost || this.Document.onDragStart || this.Document.onClick)) {
                     document.removeEventListener("touchmove", this.onTouch);
@@ -293,7 +298,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
 
     @action
     handle2PointersMove = (e: TouchEvent) => {
-        const myTouches = InteractionUtils.GetMyTargetTouches(e, this.prevPoints);
+        const myTouches = InteractionUtils.GetMyTargetTouches(e, this.prevPoints, true);
         const pt1 = myTouches[0];
         const pt2 = myTouches[1];
         const oldPoint1 = this.prevPoints.get(pt1.identifier);
@@ -363,6 +368,12 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     }
 
     onPointerDown = (e: React.PointerEvent): void => {
+        if (this.onPointerDownHandler && this.onPointerDownHandler.script) {
+            this.onPointerDownHandler.script.run({ this: this.Document.isTemplateField && this.props.DataDoc ? this.props.DataDoc : this.props.Document }, console.log);
+            document.removeEventListener("pointerup", this.onPointerUp);
+            document.addEventListener("pointerup", this.onPointerUp);
+            return;
+        }
         // console.log(e.button)
         // console.log(e.nativeEvent)
         // continue if the event hasn't been canceled AND we are using a moues or this is has an onClick or onDragStart function (meaning it is a button document)
@@ -412,6 +423,11 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     }
 
     onPointerUp = (e: PointerEvent): void => {
+        if (this.onPointerUpHandler && this.onPointerUpHandler.script && !InteractionUtils.IsType(e, InteractionUtils.PENTYPE)) {
+            this.onPointerUpHandler.script.run({ this: this.Document.isTemplateField && this.props.DataDoc ? this.props.DataDoc : this.props.Document }, console.log);
+            document.removeEventListener("pointerup", this.onPointerUp);
+            return;
+        }
         document.removeEventListener("pointermove", this.onPointerMove);
         document.removeEventListener("pointerup", this.onPointerUp);
         this._doubleTap = (Date.now() - this._lastTap < 300 && e.button === 0 && Math.abs(e.clientX - this._downX) < 2 && Math.abs(e.clientY - this._downY) < 2);
diff --git a/src/new_fields/documentSchemas.ts b/src/new_fields/documentSchemas.ts
index 21e69fbed..1cba3cba9 100644
--- a/src/new_fields/documentSchemas.ts
+++ b/src/new_fields/documentSchemas.ts
@@ -20,6 +20,8 @@ export const documentSchema = createSchema({
     dropAction: "string",       // override specifying what should happen when this document is dropped (can be "alias" or "copy")
     removeDropProperties: listSpec("string"), // properties that should be removed from the alias/copy/etc of this document when it is dropped
     onClick: ScriptField,       // script to run when document is clicked (can be overriden by an onClick prop)
+    onPointerDown: ScriptField,       // script to run when document is clicked (can be overriden by an onClick prop)
+    onPointerUp: ScriptField,       // script to run when document is clicked (can be overriden by an onClick prop)
     onDragStart: ScriptField,   // script to run when document is dragged (without being selected).  the script should return the Doc to be dropped.
     dragFactory: Doc,           // the document that serves as the "template" for the onDragStart script.  ie, to drag out copies of the dragFactory document.
     ignoreAspect: "boolean",    // whether aspect ratio should be ignored when laying out or manipulating the document
diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts
index 71dd34e68..2ade6f102 100644
--- a/src/server/authentication/models/current_user_utils.ts
+++ b/src/server/authentication/models/current_user_utils.ts
@@ -110,6 +110,29 @@ export class CurrentUserUtils {
         }));
     }
 
+    static setupThumbButtons(doc: Doc) {
+        const docProtoData: { title: string, icon: string, drag?: string, ignoreClick?: boolean, pointerDown?: string, pointerUp?: string, ischecked?: string, activePen?: Doc, backgroundColor?: string, dragFactory?: Doc }[] = [
+            { title: "use pen", icon: "pen-nib", pointerUp: "resetPen()", pointerDown: 'setPen(2, this.backgroundColor)', backgroundColor: "blue", ischecked: `sameDocs(this.activePen.pen,  this)`, activePen: doc },
+            { title: "use highlighter", icon: "highlighter", pointerUp: "resetPen()", pointerDown: 'setPen(20, this.backgroundColor)', backgroundColor: "yellow", ischecked: `sameDocs(this.activePen.pen, this)`, activePen: doc },
+        ];
+        return docProtoData.map(data => Docs.Create.FontIconDocument({
+            nativeWidth: 100, nativeHeight: 100, width: 100, height: 100, dropAction: data.pointerDown ? "copy" : undefined, title: data.title, icon: data.icon, ignoreClick: data.ignoreClick,
+            onDragStart: data.drag ? ScriptField.MakeFunction(data.drag) : undefined,
+            onPointerUp: data.pointerUp ? ScriptField.MakeScript(data.pointerUp) : undefined, onPointerDown: data.pointerDown ? ScriptField.MakeScript(data.pointerDown) : undefined,
+            ischecked: data.ischecked ? ComputedField.MakeFunction(data.ischecked) : undefined, activePen: data.activePen, pointerHack: true,
+            backgroundColor: data.backgroundColor, removeDropProperties: new List<string>(["dropAction"]), dragFactory: data.dragFactory,
+        }));
+    }
+
+    static setupThumbDoc(userDoc: Doc) {
+        if (!userDoc.thumbDoc) {
+            return Docs.Create.MasonryDocument(CurrentUserUtils.setupThumbButtons(userDoc), {
+                width: 300, columnWidth: 100, ignoreClick: true, lockedPosition: true, chromeStatus: "disabled", title: "buttons", autoHeight: true, yMargin: 5
+            });
+        }
+        return userDoc.thumbDoc;
+    }
+
     static setupMobileDoc(userDoc: Doc) {
         return userDoc.activeMoble ?? Docs.Create.MasonryDocument(CurrentUserUtils.setupMobileButtons(userDoc), {
             columnWidth: 100, ignoreClick: true, lockedPosition: true, chromeStatus: "disabled", title: "buttons", autoHeight: true, yMargin: 5
-- 
cgit v1.2.3-70-g09d2


From f970dd586c0914847b5a59951f586dad93a2cf04 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Wed, 22 Jan 2020 22:04:46 -0500
Subject: streamling templates.

---
 src/client/documents/Documents.ts                  |  2 +-
 src/client/util/DropConverter.ts                   |  4 +-
 src/client/views/DocComponent.tsx                  |  4 +-
 src/client/views/DocumentDecorations.tsx           |  2 +-
 src/client/views/InkingControl.tsx                 |  2 +-
 .../views/collections/CollectionStackingView.tsx   |  2 +-
 src/client/views/collections/CollectionSubView.tsx |  8 +--
 .../views/collections/CollectionTreeView.tsx       |  6 +--
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  2 +-
 src/client/views/nodes/ButtonBox.tsx               |  2 +-
 src/client/views/nodes/DocumentView.tsx            |  8 +--
 src/client/views/nodes/FormattedTextBox.tsx        |  2 +-
 src/new_fields/Doc.ts                              | 63 +++++++++++-----------
 src/new_fields/documentSchemas.ts                  |  2 +-
 14 files changed, 55 insertions(+), 54 deletions(-)

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index e86ed52f3..6132f787b 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -76,7 +76,7 @@ export interface DocumentOptions {
     preventTreeViewOpen?: boolean; // ignores the treeViewOpen Doc flag which allows a treeViewItem's expande/collapse state to be independent of other views of the same document in the tree view
     layout?: string | Doc;
     hideHeadings?: boolean; // whether stacking view column headings should be hidden
-    isTemplateField?: boolean;
+    isTemplateForField?: string; // the field key for which the containing document is a rendering template
     isTemplateDoc?: boolean;
     templates?: List<string>;
     viewType?: number;
diff --git a/src/client/util/DropConverter.ts b/src/client/util/DropConverter.ts
index 3e2cc6a2e..66caf52cb 100644
--- a/src/client/util/DropConverter.ts
+++ b/src/client/util/DropConverter.ts
@@ -8,7 +8,7 @@ import { Docs } from "../documents/Documents";
 import { ScriptField } from "../../new_fields/ScriptField";
 
 export function makeTemplate(doc: Doc): boolean {
-    const layoutDoc = doc.layout instanceof Doc && doc.layout.isTemplateField ? doc.layout : doc;
+    const layoutDoc = doc.layout instanceof Doc && doc.layout.isTemplateForField ? doc.layout : doc;
     const layout = StrCast(layoutDoc.layout).match(/fieldKey={'[^']*'}/)![0];
     const fieldKey = layout.replace("fieldKey={'", "").replace(/'}$/, "");
     const docs = DocListCast(layoutDoc[fieldKey]);
@@ -28,7 +28,7 @@ export function convertDropDataToButtons(data: DragManager.DocumentDragData) {
         let dbox = doc;
         // bcz: isButtonBar is intended to allow a collection of linear buttons to be dropped and nested into another collection of buttons... it's not being used yet, and isn't very elegant
         if (!doc.onDragStart && !doc.onClick && !doc.isButtonBar) {
-            const layoutDoc = doc.layout instanceof Doc && doc.layout.isTemplateField ? doc.layout : doc;
+            const layoutDoc = doc.layout instanceof Doc && doc.layout.isTemplateForField ? doc.layout : doc;
             if (layoutDoc.type === DocumentType.COL) {
                 layoutDoc.isTemplateDoc = makeTemplate(layoutDoc);
             } else {
diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index 4dbf26956..1ffbd80ca 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -34,7 +34,7 @@ export function DocExtendableComponent<P extends DocExtendableProps, T>(schemaCt
         //TODO This might be pretty inefficient if doc isn't observed, because computed doesn't cache then
         @computed get Document(): T { return schemaCtor(this.props.Document); }
         @computed get layoutDoc() { return Doc.Layout(this.props.Document); }
-        @computed get dataDoc() { return (this.props.DataDoc && (this.props.Document.isTemplateField || this.props.Document.isTemplateDoc) ? this.props.DataDoc : Doc.GetProto(this.props.Document)) as Doc; }
+        @computed get dataDoc() { return (this.props.DataDoc && (this.props.Document.isTemplateForField || this.props.Document.isTemplateDoc) ? this.props.DataDoc : Doc.GetProto(this.props.Document)) as Doc; }
         @computed get extensionDoc() { return Doc.fieldExtensionDoc(this.dataDoc, this.props.fieldKey); }
         active = (outsideReaction?: boolean) => !this.props.Document.isBackground && (this.props.Document.forceActive || this.props.isSelected(outsideReaction) || this.props.renderDepth === 0);//  && !InkingControl.Instance.selectedTool;  // bcz: inking state shouldn't affect static tools 
     }
@@ -58,7 +58,7 @@ export function DocAnnotatableComponent<P extends DocAnnotatableProps, T>(schema
         //TODO This might be pretty inefficient if doc isn't observed, because computed doesn't cache then
         @computed get Document(): T { return schemaCtor(this.props.Document); }
         @computed get layoutDoc() { return Doc.Layout(this.props.Document); }
-        @computed get dataDoc() { return (this.props.DataDoc && (this.props.Document.isTemplateField || this.props.Document.isTemplateDoc) ? this.props.DataDoc : Doc.GetProto(this.props.Document)) as Doc; }
+        @computed get dataDoc() { return (this.props.DataDoc && (this.props.Document.isTemplateForField || this.props.Document.isTemplateDoc) ? this.props.DataDoc : Doc.GetProto(this.props.Document)) as Doc; }
         @computed get extensionDoc() { return Doc.fieldExtensionDoc(this.dataDoc, this.props.fieldKey); }
         @computed get extensionDocSync() { return Doc.fieldExtensionDocSync(this.dataDoc, this.props.fieldKey); }
         @computed get annotationsKey() { return "annotations"; }
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 32fea15fb..322536b7e 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -369,7 +369,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
             ruleProvider && heading && (Doc.GetProto(ruleProvider)["ruleRounding_" + heading] = `${Math.min(100, dist)}%`);
             usingRule = usingRule || (ruleProvider && heading ? true : false);
         });
-        !usingRule && SelectionManager.SelectedDocuments().map(dv => dv.props.Document.layout instanceof Doc ? dv.props.Document.layout : dv.props.Document.isTemplateField ? dv.props.Document : Doc.GetProto(dv.props.Document)).
+        !usingRule && SelectionManager.SelectedDocuments().map(dv => dv.props.Document.layout instanceof Doc ? dv.props.Document.layout : dv.props.Document.isTemplateForField ? dv.props.Document : Doc.GetProto(dv.props.Document)).
             map(d => d.borderRounding = `${Math.min(100, dist)}%`);
         e.stopPropagation();
         e.preventDefault();
diff --git a/src/client/views/InkingControl.tsx b/src/client/views/InkingControl.tsx
index be07a9024..853d81a68 100644
--- a/src/client/views/InkingControl.tsx
+++ b/src/client/views/InkingControl.tsx
@@ -44,7 +44,7 @@ export class InkingControl {
             const oldColors = selected.map(view => {
                 const targetDoc = view.props.Document.dragFactory instanceof Doc ? view.props.Document.dragFactory :
                     view.props.Document.layout instanceof Doc ? view.props.Document.layout :
-                        view.props.Document.isTemplateField ? view.props.Document : Doc.GetProto(view.props.Document);
+                        view.props.Document.isTemplateForField ? view.props.Document : Doc.GetProto(view.props.Document);
                 const sel = window.getSelection();
                 if (StrCast(targetDoc.layout).indexOf("FormattedTextBox") !== -1 && (!sel || sel.toString() !== "")) {
                     targetDoc.color = this._selectedColor;
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 7fe42386a..b2e4b9d90 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -39,7 +39,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
     @observable _scroll = 0; // used to force the document decoration to update when scrolling
     @computed get sectionHeaders() { return Cast(this.props.Document.sectionHeaders, listSpec(SchemaHeaderField)); }
     @computed get sectionFilter() { return StrCast(this.props.Document.sectionFilter); }
-    @computed get filteredChildren() { return this.childDocs.filter(d => !d.isMinimized).map(d => (Doc.GetLayoutDataDocPair(this.props.Document, this.props.DataDoc, this.props.fieldKey, d).layout as Doc) || d); }
+    @computed get filteredChildren() { return this.childDocs.filter(d => !d.isMinimized).map(d => (Doc.GetLayoutDataDocPair(this.props.Document, this.props.DataDoc, d).layout as Doc) || d); }
     @computed get xMargin() { return NumCast(this.props.Document.xMargin, 2 * this.gridGap); }
     @computed get yMargin() { return Math.max(this.props.Document.showTitle && !this.props.Document.showTitleHover ? 30 : 0, NumCast(this.props.Document.yMargin, 2 * this.gridGap)); }
     @computed get gridGap() { return NumCast(this.props.Document.gridGap, 10); }
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 9357b0507..6c4f940b6 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -73,7 +73,7 @@ export function CollectionSubView<T>(schemaCtor: (doc: Doc) => T) {
                         this.childDocs.map(async doc => !Doc.AreProtosEqual(args[1] as Doc, (await doc).layout as Doc) && Doc.ApplyTemplateTo(args[1] as Doc, (await doc), "layoutFromParent"));
                     }
                     else if (!(args[1] instanceof Promise)) {
-                        this.childDocs.filter(d => !d.isTemplateField).map(async doc => doc.layoutKey === "layoutFromParent" && (doc.layoutKey = "layout"));
+                        this.childDocs.filter(d => !d.isTemplateForField).map(async doc => doc.layoutKey === "layoutFromParent" && (doc.layoutKey = "layout"));
                     }
                 });
 
@@ -82,7 +82,7 @@ export function CollectionSubView<T>(schemaCtor: (doc: Doc) => T) {
             this._childLayoutDisposer && this._childLayoutDisposer();
         }
 
-        @computed get dataDoc() { return this.props.DataDoc && this.props.Document.isTemplateField ? Doc.GetProto(this.props.DataDoc) : Doc.GetProto(this.props.Document); }
+        @computed get dataDoc() { return this.props.DataDoc && this.props.Document.isTemplateForField ? Doc.GetProto(this.props.DataDoc) : Doc.GetProto(this.props.Document); }
         @computed get extensionDoc() { return Doc.fieldExtensionDoc(this.dataDoc, this.props.fieldKey); }
 
         // The data field for rendering this collection will be on the this.props.Document unless we're rendering a template in which case we try to use props.DataDoc.
@@ -102,8 +102,8 @@ export function CollectionSubView<T>(schemaCtor: (doc: Doc) => T) {
         }
 
         get childLayoutPairs(): { layout: Doc; data: Doc; }[] {
-            const { Document, DataDoc, fieldKey } = this.props;
-            const validPairs = this.childDocs.map(doc => Doc.GetLayoutDataDocPair(Document, DataDoc, fieldKey, doc)).filter(pair => pair.layout);
+            const { Document, DataDoc } = this.props;
+            const validPairs = this.childDocs.map(doc => Doc.GetLayoutDataDocPair(Document, DataDoc, doc)).filter(pair => pair.layout);
             return validPairs.map(({ data, layout }) => ({ data: data!, layout: layout! })); // this mapping is a bit of a hack to coerce types
         }
         get childDocList() {
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 6b6fdff50..2c8c53f97 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -375,7 +375,7 @@ class TreeView extends React.Component<TreeViewProps> {
         if (this.props.onCheckedClick && this.props.document.type !== DocumentType.COL) {
             // this.props.document.treeViewChecked = this.props.document.treeViewChecked === "check" ? "x" : this.props.document.treeViewChecked === "x" ? undefined : "check";
             ScriptCast(this.props.onCheckedClick).script.run({
-                this: this.props.document.isTemplateField && this.props.dataDoc ? this.props.dataDoc : this.props.document,
+                this: this.props.document.isTemplateForField && this.props.dataDoc ? this.props.dataDoc : this.props.document,
                 heading: this.props.containingCollection.title,
                 checked: this.props.document.treeViewChecked === "check" ? "x" : this.props.document.treeViewChecked === "x" ? undefined : "check",
                 containingTreeView: this.props.treeViewId,
@@ -519,7 +519,7 @@ class TreeView extends React.Component<TreeViewProps> {
 
         const rowWidth = () => panelWidth() - 20;
         return docs.map((child, i) => {
-            const pair = Doc.GetLayoutDataDocPair(containingCollection, dataDoc, key, child);
+            const pair = Doc.GetLayoutDataDocPair(containingCollection, dataDoc, child);
             if (!pair.layout || pair.data instanceof Promise) {
                 return (null);
             }
@@ -646,7 +646,7 @@ export class CollectionTreeView extends CollectionSubView(Document) {
                 ], { autoHeight: true, chromeStatus: "disabled", title: "detailed layout stack" });
                 detailedLayout.isTemplateDoc = makeTemplate(detailedLayout);
 
-                const cardLayout = ImageDocument(fallbackImg, { isTemplateDoc: true, isTemplateField: true }); // this acts like a template doc and a template field ... a little weird, but seems to work?
+                const cardLayout = ImageDocument(fallbackImg, { isTemplateDoc: true, isTemplateForField: "hero", }); // this acts like a template doc and a template field ... a little weird, but seems to work?
                 cardLayout.proto!.layout = ImageBox.LayoutString("hero");
                 cardLayout.showTitle = "title";
                 cardLayout.showTitleHover = "titlehover";
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index a7e4fce4e..aa1559416 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -833,7 +833,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
         this.Document.isRuleProvider && this.childLayoutPairs.map(pair =>
             // iterate over the children of a displayed document (or if the displayed document is a template, iterate over the children of that template)
             DocListCast(Doc.Layout(pair.layout).data).map(heading => {
-                const headingPair = Doc.GetLayoutDataDocPair(this.props.Document, this.props.DataDoc, this.props.fieldKey, heading);
+                const headingPair = Doc.GetLayoutDataDocPair(this.props.Document, this.props.DataDoc, heading);
                 const headingLayout = headingPair.layout && (pair.layout.data_ext instanceof Doc) && (pair.layout.data_ext[`Layout[${headingPair.layout[Id]}]`] as Doc) || headingPair.layout;
                 if (headingLayout && NumCast(headingLayout.heading) > 0 && headingLayout.backgroundColor !== headingLayout.defaultBackgroundColor) {
                     Doc.GetProto(this.props.Document)["ruleColor_" + NumCast(headingLayout.heading)] = headingLayout.backgroundColor;
diff --git a/src/client/views/nodes/ButtonBox.tsx b/src/client/views/nodes/ButtonBox.tsx
index d29fe1711..ee48b47b7 100644
--- a/src/client/views/nodes/ButtonBox.tsx
+++ b/src/client/views/nodes/ButtonBox.tsx
@@ -36,7 +36,7 @@ export class ButtonBox extends DocComponent<FieldViewProps, ButtonDocument>(Butt
 
     @computed get dataDoc() {
         return this.props.DataDoc &&
-            (this.Document.isTemplateField || BoolCast(this.props.DataDoc.isTemplateField) ||
+            (this.Document.isTemplateForField || BoolCast(this.props.DataDoc.isTemplateForField) ||
                 this.props.DataDoc.layout === this.props.Document) ? this.props.DataDoc : Doc.GetProto(this.props.Document);
     }
 
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 36f2e7a4d..b491acb8d 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -268,7 +268,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                 SelectionManager.DeselectAll();
                 Doc.UnBrushDoc(this.props.Document);
             } else if (this.onClickHandler && this.onClickHandler.script) {
-                this.onClickHandler.script.run({ this: this.Document.isTemplateField && this.props.DataDoc ? this.props.DataDoc : this.props.Document, containingCollection: this.props.ContainingCollectionDoc }, console.log);
+                this.onClickHandler.script.run({ this: this.Document.isTemplateForField && this.props.DataDoc ? this.props.DataDoc : this.props.Document, containingCollection: this.props.ContainingCollectionDoc }, console.log);
             } else if (this.Document.type === DocumentType.BUTTON) {
                 ScriptBox.EditButtonScript("On Button Clicked ...", this.props.Document, "onClick", e.clientX, e.clientY);
             } else if (this.props.Document.isButton === "Selector") {  // this should be moved to an OnClick script
@@ -438,7 +438,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
 
     onPointerDown = (e: React.PointerEvent): void => {
         if (this.onPointerDownHandler && this.onPointerDownHandler.script) {
-            this.onPointerDownHandler.script.run({ this: this.Document.isTemplateField && this.props.DataDoc ? this.props.DataDoc : this.props.Document }, console.log);
+            this.onPointerDownHandler.script.run({ this: this.Document.isTemplateForField && this.props.DataDoc ? this.props.DataDoc : this.props.Document }, console.log);
             document.removeEventListener("pointerup", this.onPointerUp);
             document.addEventListener("pointerup", this.onPointerUp);
             return;
@@ -495,7 +495,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
 
     onPointerUp = (e: PointerEvent): void => {
         if (this.onPointerUpHandler && this.onPointerUpHandler.script && !InteractionUtils.IsType(e, InteractionUtils.PENTYPE)) {
-            this.onPointerUpHandler.script.run({ this: this.Document.isTemplateField && this.props.DataDoc ? this.props.DataDoc : this.props.Document }, console.log);
+            this.onPointerUpHandler.script.run({ this: this.Document.isTemplateForField && this.props.DataDoc ? this.props.DataDoc : this.props.Document }, console.log);
             document.removeEventListener("pointerup", this.onPointerUp);
             return;
         }
@@ -996,7 +996,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                 color: StrCast(this.Document.color),
                 outline: highlighting && !borderRounding ? `${highlightColors[fullDegree]} ${highlightStyles[fullDegree]} ${localScale}px` : "solid 0px",
                 border: highlighting && borderRounding ? `${highlightStyles[fullDegree]} ${highlightColors[fullDegree]} ${localScale}px` : undefined,
-                boxShadow: this.props.Document.isTemplateField ? "black 0.2vw 0.2vw 0.8vw" : undefined,
+                boxShadow: this.props.Document.isTemplateForField ? "black 0.2vw 0.2vw 0.8vw" : undefined,
                 background: this.layoutDoc.type === DocumentType.FONTICON || this.layoutDoc.viewType === CollectionViewType.Linear ? undefined : backgroundColor,
                 width: animwidth,
                 height: animheight,
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 1cd5cdcea..3814f02da 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -1101,7 +1101,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
                 this.layoutDoc.limitHeight = undefined;
                 this.layoutDoc.autoHeight = false;
             }
-            const nh = this.Document.isTemplateField ? 0 : NumCast(this.dataDoc.nativeHeight, 0);
+            const nh = this.Document.isTemplateForField ? 0 : NumCast(this.dataDoc.nativeHeight, 0);
             const dh = NumCast(this.layoutDoc.height, 0);
             const newHeight = Math.max(10, (nh ? dh / nh * scrollHeight : scrollHeight) + (this.props.ChromeHeight ? this.props.ChromeHeight() : 0));
             if (Math.abs(newHeight - dh) > 1) { // bcz: Argh!  without this, we get into a React crash if the same document is opened in a freeform view and in the treeview.  no idea why, but after dragging the freeform document, selecting it, and selecting text, it will compute to 1 pixel higher than the treeview which causes a cycle
diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts
index e9f8e6429..669e7a72f 100644
--- a/src/new_fields/Doc.ts
+++ b/src/new_fields/Doc.ts
@@ -431,48 +431,49 @@ export namespace Doc {
 
     //
     // Determines whether the combination of the layoutDoc and dataDoc represents
-    // a template relationship.  If so, the layoutDoc will be expanded into a new
-    // document that inherits the properties of the original layout while allowing
-    // for individual layout properties to be overridden in the expanded layout.
+    // a template relationship :  there is a dataDoc and it doesn't match the layoutDoc an
+    // the lyouatDoc's layout is layout string (not a document) 
     //
     export function WillExpandTemplateLayout(layoutDoc: Doc, dataDoc?: Doc) {
-        return BoolCast(layoutDoc.isTemplateField) && dataDoc && layoutDoc !== dataDoc && !(layoutDoc[StrCast(layoutDoc.layoutKey, "layout")] instanceof Doc);
+        return layoutDoc.isTemplateForField && dataDoc && layoutDoc !== dataDoc && !(Doc.LayoutField(layoutDoc) instanceof Doc);
     }
 
     //
-    // Returns an expanded template layout for a target data document.
-    // First it checks if an expanded layout already exists -- if so it will be stored on the dataDoc
-    // using the template layout doc's id as the field key.
-    // If it doesn't find the expanded layout, then it makes a delegate of the template layout and
-    // saves it on the data doc indexed by the template layout's id
+    // Returns an expanded template layout for a target data document if there is a template relationship
+    // between the two. If so, the layoutDoc is expanded into a new document that inherits the properties 
+    // of the original layout while allowing for individual layout properties to be overridden in the expanded layout.
     //
     export function expandTemplateLayout(templateLayoutDoc: Doc, dataDoc?: Doc) {
         if (!WillExpandTemplateLayout(templateLayoutDoc, dataDoc) || !dataDoc) return templateLayoutDoc;
-        // if we have a data doc that doesn't match the layout, then we're rendering a template.
-        // ... which means we change the layout to be an expanded view of the template layout.  
-        // This allows the view override the template's properties and be referenceable as its own document.
 
+        const templateField = StrCast(templateLayoutDoc.isTemplateForField);  // the field that the template renders
+        const extensionDoc = fieldExtensionDoc(dataDoc, templateField); // an extension doc for the field that the template renders
+        // First it checks if an expanded layout already exists -- if so it will be stored on the dataDoc
+        // using the template layout doc's id as the field key.
+        // If it doesn't find the expanded layout, then it makes a delegate of the template layout and
+        // saves it on the data doc indexed by the template layout's id.
+        //
         const expandedLayoutFieldKey = "Layout[" + templateLayoutDoc[Id] + "]";
-        const expandedTemplateLayout = dataDoc[expandedLayoutFieldKey];
-        if (expandedTemplateLayout instanceof Doc) {
-            return expandedTemplateLayout;
-        }
-        if (expandedTemplateLayout === undefined) {
-            setTimeout(() => dataDoc[expandedLayoutFieldKey] === undefined &&
-                (dataDoc[expandedLayoutFieldKey] = Doc.MakeDelegate(templateLayoutDoc, undefined, "[" + templateLayoutDoc.title + "]")), 0);
+        const expandedTemplateLayout = extensionDoc?.[expandedLayoutFieldKey];
+        if (expandedTemplateLayout === undefined && extensionDoc) {
+            setTimeout(() => {
+                if (!extensionDoc[expandedLayoutFieldKey]) {
+                    const newLayoutDoc = Doc.MakeDelegate(templateLayoutDoc, undefined, "[" + templateLayoutDoc.title + "]");
+                    extensionDoc[expandedLayoutFieldKey] = newLayoutDoc;
+                    newLayoutDoc.resolvedDataDoc = dataDoc;
+                }
+            }, 0);
         }
-        return undefined; // use the templateLayout when it's not a template or the expandedTemplate is pending.
+        return expandedTemplateLayout instanceof Doc ? expandedTemplateLayout : undefined; // layout is undefined if the expandedTemplate is pending.
     }
 
-    export function GetLayoutDataDocPair(doc: Doc, dataDoc: Doc | undefined, fieldKey: string, childDocLayout: Doc) {
-        let layoutDoc: Doc | undefined = childDocLayout;
-        const resolvedDataDoc = !doc.isTemplateField && dataDoc !== doc && dataDoc ? Doc.GetDataDoc(dataDoc) : undefined;
-        if (resolvedDataDoc && Doc.WillExpandTemplateLayout(childDocLayout, resolvedDataDoc)) {
-            const extensionDoc = fieldExtensionDoc(resolvedDataDoc, StrCast(childDocLayout.templateField, StrCast(childDocLayout.title)));
-            layoutDoc = Doc.expandTemplateLayout(childDocLayout, extensionDoc !== resolvedDataDoc ? extensionDoc : undefined);
-            setTimeout(async () => layoutDoc && (layoutDoc.resolvedDataDoc = await resolvedDataDoc), 0);
-        } else layoutDoc = childDocLayout;
-        return { layout: layoutDoc, data: resolvedDataDoc };
+    // returns the layout/data doc pair to render for the specified childDoc of a collection.
+    // The containerDoc is treated as a template if its containerDataDoc has a value.  If so, 
+    // the childDoc is treated as a layout description for some field of the container doc's data doc.
+    export function GetLayoutDataDocPair(containerDoc: Doc, containerDataDoc: Opt<Doc>, childDoc: Doc) {
+        const resolvedDataDoc = containerDoc.isTemplateForField || containerDataDoc === containerDoc || !containerDataDoc ?
+            undefined : Doc.GetDataDoc(containerDataDoc);
+        return { layout: Doc.expandTemplateLayout(childDoc, resolvedDataDoc), data: resolvedDataDoc };
     }
 
     //
@@ -483,6 +484,7 @@ export namespace Doc {
     // to store annotations, ink, and other data.
     //
     export function fieldExtensionDoc(doc: Doc, fieldKey: string) {
+        if (!fieldKey) return undefined;
         const extension = doc[fieldKey + "_ext"];
         if (doc instanceof Doc && extension === undefined) {
             setTimeout(() => CreateDocumentExtensionForField(doc, fieldKey), 0);
@@ -616,8 +618,7 @@ export namespace Doc {
         const metadataFieldKey = StrCast(templateField.title).replace(/^-/, "");
 
         // update the original template to mark it as a template
-        templateField.templateField = metadataFieldKey;
-        templateField.isTemplateField = true;
+        templateField.isTemplateForField = metadataFieldKey;
         templateField.title = metadataFieldKey;
         // templateField.showTitle = suppressTitle ? undefined : "title";
 
diff --git a/src/new_fields/documentSchemas.ts b/src/new_fields/documentSchemas.ts
index 3683e5820..180c52b3d 100644
--- a/src/new_fields/documentSchemas.ts
+++ b/src/new_fields/documentSchemas.ts
@@ -26,7 +26,7 @@ export const documentSchema = createSchema({
     dragFactory: Doc,           // the document that serves as the "template" for the onDragStart script.  ie, to drag out copies of the dragFactory document.
     ignoreAspect: "boolean",    // whether aspect ratio should be ignored when laying out or manipulating the document
     autoHeight: "boolean",      // whether the height of the document should be computed automatically based on its contents
-    isTemplateField: "boolean", // whether this document acts as a template layout for describing how other documents should be displayed
+    isTemplateForField: "string",// when specifies a field key, then the containing document is a template that renders the specified field
     isBackground: "boolean",    // whether document is a background element and ignores input events (can only selet with marquee)
     type: "string",             // enumerated type of document
     treeViewOpen: "boolean",    //  flag denoting whether the documents sub-tree (contents) is visible or hidden
-- 
cgit v1.2.3-70-g09d2


From 1348444b573ad7d50787b1c0a5aa46c1d267f9ef Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Wed, 22 Jan 2020 23:53:10 -0500
Subject: small cleanups for exceptions

---
 src/client/views/InkingControl.tsx    | 50 +++++++++++++++++------------------
 src/client/views/search/SearchBox.tsx |  3 ++-
 src/new_fields/Doc.ts                 |  8 +++---
 3 files changed, 30 insertions(+), 31 deletions(-)

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

diff --git a/src/client/views/InkingControl.tsx b/src/client/views/InkingControl.tsx
index 853d81a68..ab53b76be 100644
--- a/src/client/views/InkingControl.tsx
+++ b/src/client/views/InkingControl.tsx
@@ -57,31 +57,31 @@ export class InkingControl {
                 let matchedColor = this._selectedColor;
                 const cvd = view.props.ContainingCollectionDoc;
                 let ruleProvider = view.props.ruleProvider;
-                if (cvd) {
-                    if (!cvd.colorPalette) {
-                        const defaultPalette = ["rg(114,229,239)", "rgb(255,246,209)", "rgb(255,188,156)", "rgb(247,220,96)", "rgb(122,176,238)",
-                            "rgb(209,150,226)", "rgb(127,235,144)", "rgb(252,188,189)", "rgb(247,175,81)",];
-                        const colorPalette = Cast(cvd.colorPalette, listSpec("string"));
-                        if (!colorPalette) cvd.colorPalette = new List<string>(defaultPalette);
-                    }
-                    const cp = Cast(cvd.colorPalette, listSpec("string")) as string[];
-                    let closest = 0;
-                    let dist = 10000000;
-                    const ccol = Utils.fromRGBAstr(StrCast(targetDoc.backgroundColor));
-                    for (let i = 0; i < cp.length; i++) {
-                        const cpcol = Utils.fromRGBAstr(cp[i]);
-                        const d = Math.sqrt((ccol.r - cpcol.r) * (ccol.r - cpcol.r) + (ccol.b - cpcol.b) * (ccol.b - cpcol.b) + (ccol.g - cpcol.g) * (ccol.g - cpcol.g));
-                        if (d < dist) {
-                            dist = d;
-                            closest = i;
-                        }
-                    }
-                    cp[closest] = "rgba(" + color.rgb.r + "," + color.rgb.g + "," + color.rgb.b + "," + color.rgb.a + ")";
-                    cvd.colorPalette = new List(cp);
-                    matchedColor = cp[closest];
-                    ruleProvider = (view.props.Document.heading && ruleProvider) ? ruleProvider : undefined;
-                    ruleProvider && ((Doc.GetProto(ruleProvider)["ruleColor_" + NumCast(view.props.Document.heading)] = Utils.toRGBAstr(color.rgb)));
-                }
+                // if (cvd) {
+                //     if (!cvd.colorPalette) {
+                //         const defaultPalette = ["rg(114,229,239)", "rgb(255,246,209)", "rgb(255,188,156)", "rgb(247,220,96)", "rgb(122,176,238)",
+                //             "rgb(209,150,226)", "rgb(127,235,144)", "rgb(252,188,189)", "rgb(247,175,81)",];
+                //         const colorPalette = Cast(cvd.colorPalette, listSpec("string"));
+                //         if (!colorPalette) cvd.colorPalette = new List<string>(defaultPalette);
+                //     }
+                //     const cp = Cast(cvd.colorPalette, listSpec("string")) as string[];
+                //     let closest = 0;
+                //     let dist = 10000000;
+                //     const ccol = Utils.fromRGBAstr(StrCast(targetDoc.backgroundColor));
+                //     for (let i = 0; i < cp.length; i++) {
+                //         const cpcol = Utils.fromRGBAstr(cp[i]);
+                //         const d = Math.sqrt((ccol.r - cpcol.r) * (ccol.r - cpcol.r) + (ccol.b - cpcol.b) * (ccol.b - cpcol.b) + (ccol.g - cpcol.g) * (ccol.g - cpcol.g));
+                //         if (d < dist) {
+                //             dist = d;
+                //             closest = i;
+                //         }
+                //     }
+                //     cp[closest] = "rgba(" + color.rgb.r + "," + color.rgb.g + "," + color.rgb.b + "," + color.rgb.a + ")";
+                //     cvd.colorPalette = new List(cp);
+                //     matchedColor = cp[closest];
+                //     ruleProvider = (view.props.Document.heading && ruleProvider) ? ruleProvider : undefined;
+                //     ruleProvider && ((Doc.GetProto(ruleProvider)["ruleColor_" + NumCast(view.props.Document.heading)] = Utils.toRGBAstr(color.rgb)));
+                // }
                 (!ruleProvider && targetDoc) && (Doc.Layout(view.props.Document).backgroundColor = matchedColor);
 
                 return {
diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx
index dd1ac7421..f7ae83b2f 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -267,10 +267,11 @@ export class SearchBox extends React.Component {
 
     @action
     resultsScrolled = (e?: React.UIEvent<HTMLDivElement>) => {
+        if (!this.resultsRef.current) return;
         const scrollY = e ? e.currentTarget.scrollTop : this.resultsRef.current ? this.resultsRef.current.scrollTop : 0;
         const itemHght = 53;
         const startIndex = Math.floor(Math.max(0, scrollY / itemHght));
-        const endIndex = Math.ceil(Math.min(this._numTotalResults - 1, startIndex + (this.resultsRef.current!.getBoundingClientRect().height / itemHght)));
+        const endIndex = Math.ceil(Math.min(this._numTotalResults - 1, startIndex + (this.resultsRef.current.getBoundingClientRect().height / itemHght)));
 
         this._endIndex = endIndex === -1 ? 12 : endIndex;
 
diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts
index 669e7a72f..4b7f10f91 100644
--- a/src/new_fields/Doc.ts
+++ b/src/new_fields/Doc.ts
@@ -467,12 +467,10 @@ export namespace Doc {
         return expandedTemplateLayout instanceof Doc ? expandedTemplateLayout : undefined; // layout is undefined if the expandedTemplate is pending.
     }
 
-    // returns the layout/data doc pair to render for the specified childDoc of a collection.
-    // The containerDoc is treated as a template if its containerDataDoc has a value.  If so, 
-    // the childDoc is treated as a layout description for some field of the container doc's data doc.
+    // if the childDoc is a template for a field, then this will return the expanded layout with its data doc.
+    // otherwise, it just returns the childDoc
     export function GetLayoutDataDocPair(containerDoc: Doc, containerDataDoc: Opt<Doc>, childDoc: Doc) {
-        const resolvedDataDoc = containerDoc.isTemplateForField || containerDataDoc === containerDoc || !containerDataDoc ?
-            undefined : Doc.GetDataDoc(containerDataDoc);
+        const resolvedDataDoc = containerDataDoc === containerDoc || !containerDataDoc ? undefined : Doc.GetDataDoc(containerDataDoc);
         return { layout: Doc.expandTemplateLayout(childDoc, resolvedDataDoc), data: resolvedDataDoc };
     }
 
-- 
cgit v1.2.3-70-g09d2


From 0142f4e14cc8e291ee5acbae3cc4b81c95c4634a Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Thu, 23 Jan 2020 00:40:55 -0500
Subject: got rid of rule provider stuff.  fixed panning in freeform view with
 pivot layouts

---
 src/client/util/RichTextMenu.tsx                   | 20 ++---------
 src/client/util/RichTextRules.ts                   | 24 -------------
 src/client/util/RichTextSchema.tsx                 |  1 -
 src/client/views/DocumentDecorations.tsx           |  9 +----
 src/client/views/GestureOverlay.tsx                |  1 -
 src/client/views/InkingControl.tsx                 | 29 +--------------
 src/client/views/MainView.tsx                      |  4 ---
 src/client/views/OverlayView.tsx                   |  1 -
 src/client/views/Palette.tsx                       |  1 -
 .../views/collections/CollectionDockingView.tsx    |  1 -
 .../views/collections/CollectionLinearView.tsx     |  1 -
 .../views/collections/CollectionSchemaCells.tsx    |  1 -
 .../views/collections/CollectionSchemaView.tsx     |  1 -
 .../views/collections/CollectionStackingView.tsx   |  3 +-
 src/client/views/collections/CollectionSubView.tsx |  1 -
 .../views/collections/CollectionTreeView.tsx       |  3 --
 .../collectionFreeForm/CollectionFreeFormView.tsx  | 42 +++++-----------------
 .../views/nodes/CollectionFreeFormDocumentView.tsx |  4 +--
 .../views/nodes/ContentFittingDocumentView.tsx     |  2 --
 src/client/views/nodes/DocumentBox.tsx             |  1 -
 src/client/views/nodes/DocumentView.tsx            |  8 ++---
 src/client/views/nodes/FieldView.tsx               |  1 -
 src/client/views/nodes/FormattedTextBox.tsx        | 33 -----------------
 src/client/views/nodes/FormattedTextBoxComment.tsx |  1 -
 src/client/views/nodes/ImageBox.tsx                |  1 -
 src/client/views/nodes/KeyValuePair.tsx            |  1 -
 src/client/views/nodes/VideoBox.tsx                |  1 -
 src/client/views/nodes/WebBox.tsx                  |  1 -
 src/client/views/pdf/PDFViewer.tsx                 |  1 -
 .../views/presentationview/PresElementBox.tsx      |  1 -
 src/client/views/search/SearchItem.tsx             |  1 -
 src/mobile/MobileInterface.tsx                     |  1 -
 32 files changed, 16 insertions(+), 185 deletions(-)

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

diff --git a/src/client/util/RichTextMenu.tsx b/src/client/util/RichTextMenu.tsx
index eb5c90654..e07efe056 100644
--- a/src/client/util/RichTextMenu.tsx
+++ b/src/client/util/RichTextMenu.tsx
@@ -367,27 +367,11 @@ export default class RichTextMenu extends AntimodeMenu {
     }
 
     changeFontSize = (mark: Mark, view: EditorView) => {
-        const size = mark.attrs.fontSize;
-        if (this.editorProps) {
-            const ruleProvider = this.editorProps.ruleProvider;
-            const heading = NumCast(this.editorProps.Document.heading);
-            if (ruleProvider && heading) {
-                ruleProvider["ruleSize_" + heading] = size;
-            }
-        }
-        this.setMark(view.state.schema.marks.pFontSize.create({ fontSize: size }), view.state, view.dispatch);
+        this.setMark(view.state.schema.marks.pFontSize.create({ fontSize: mark.attrs.fontSize }), view.state, view.dispatch);
     }
 
     changeFontFamily = (mark: Mark, view: EditorView) => {
-        const fontName = mark.attrs.family;
-        if (this.editorProps) {
-            const ruleProvider = this.editorProps.ruleProvider;
-            const heading = NumCast(this.editorProps.Document.heading);
-            if (ruleProvider && heading) {
-                ruleProvider["ruleFont_" + heading] = fontName;
-            }
-        }
-        this.setMark(view.state.schema.marks.pFontFamily.create({ family: fontName }), view.state, view.dispatch);
+        this.setMark(view.state.schema.marks.pFontFamily.create({ family: mark.attrs.family }), view.state, view.dispatch);
     }
 
     // TODO: remove doesn't work
diff --git a/src/client/util/RichTextRules.ts b/src/client/util/RichTextRules.ts
index e20abb04c..0ee9481f0 100644
--- a/src/client/util/RichTextRules.ts
+++ b/src/client/util/RichTextRules.ts
@@ -67,12 +67,6 @@ export const inpRules = {
             new RegExp(/^%([0-9]+)\s$/),
             (state, match, start, end) => {
                 const size = Number(match[1]);
-                const ruleProvider = FormattedTextBox.FocusedBox!.props.ruleProvider;
-                const heading = NumCast(FormattedTextBox.FocusedBox!.props.Document.heading);
-                if (ruleProvider && heading) {
-                    (Cast(FormattedTextBox.FocusedBox!.props.Document, Doc) as Doc).heading = size;
-                    return state.tr.deleteRange(start, end);
-                }
                 return state.tr.deleteRange(start, end).addStoredMark(schema.marks.pFontSize.create({ fontSize: size }));
             }),
 
@@ -175,12 +169,6 @@ export const inpRules = {
             (state, match, start, end) => {
                 const node = (state.doc.resolve(start) as any).nodeAfter;
                 const sm = state.storedMarks || undefined;
-                const ruleProvider = FormattedTextBox.FocusedBox!.props.ruleProvider;
-                const heading = NumCast(FormattedTextBox.FocusedBox!.props.Document.heading);
-                if (ruleProvider && heading) {
-                    ruleProvider["ruleAlign_" + heading] = "center";
-                    return node ? state.tr.deleteRange(start, end).setStoredMarks([...node.marks, ...(sm ? sm : [])]) : state.tr;
-                }
                 const replaced = node ? state.tr.replaceRangeWith(start, end, schema.nodes.paragraph.create({ align: "center" })).setStoredMarks([...node.marks, ...(sm ? sm : [])]) :
                     state.tr;
                 return replaced.setSelection(new TextSelection(replaced.doc.resolve(end - 2)));
@@ -191,12 +179,6 @@ export const inpRules = {
             (state, match, start, end) => {
                 const node = (state.doc.resolve(start) as any).nodeAfter;
                 const sm = state.storedMarks || undefined;
-                const ruleProvider = FormattedTextBox.FocusedBox!.props.ruleProvider;
-                const heading = NumCast(FormattedTextBox.FocusedBox!.props.Document.heading);
-                if (ruleProvider && heading) {
-                    ruleProvider["ruleAlign_" + heading] = "left";
-                    return node ? state.tr.deleteRange(start, end).setStoredMarks([...node.marks, ...(sm ? sm : [])]) : state.tr;
-                }
                 const replaced = node ? state.tr.replaceRangeWith(start, end, schema.nodes.paragraph.create({ align: "left" })).setStoredMarks([...node.marks, ...(sm ? sm : [])]) :
                     state.tr;
                 return replaced.setSelection(new TextSelection(replaced.doc.resolve(end - 2)));
@@ -207,12 +189,6 @@ export const inpRules = {
             (state, match, start, end) => {
                 const node = (state.doc.resolve(start) as any).nodeAfter;
                 const sm = state.storedMarks || undefined;
-                const ruleProvider = FormattedTextBox.FocusedBox!.props.ruleProvider;
-                const heading = NumCast(FormattedTextBox.FocusedBox!.props.Document.heading);
-                if (ruleProvider && heading) {
-                    ruleProvider["ruleAlign_" + heading] = "right";
-                    return node ? state.tr.deleteRange(start, end).setStoredMarks([...node.marks, ...(sm ? sm : [])]) : state.tr;
-                }
                 const replaced = node ? state.tr.replaceRangeWith(start, end, schema.nodes.paragraph.create({ align: "right" })).setStoredMarks([...node.marks, ...(sm ? sm : [])]) :
                     state.tr;
                 return replaced.setSelection(new TextSelection(replaced.doc.resolve(end - 2)));
diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx
index 5751c8c7e..fe7ab31a8 100644
--- a/src/client/util/RichTextSchema.tsx
+++ b/src/client/util/RichTextSchema.tsx
@@ -761,7 +761,6 @@ export class DashDocView {
                     fitToBox={BoolCast(dashDoc.fitToBox)}
                     addDocument={returnFalse}
                     removeDocument={removeDoc}
-                    ruleProvider={undefined}
                     ScreenToLocalTransform={this.getDocTransform}
                     addDocTab={self._textBox.props.addDocTab}
                     pinToPres={returnFalse}
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 322536b7e..e6a119d1f 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -362,14 +362,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
     onRadiusMove = (e: PointerEvent): void => {
         let dist = Math.sqrt((e.clientX - this._radiusDown[0]) * (e.clientX - this._radiusDown[0]) + (e.clientY - this._radiusDown[1]) * (e.clientY - this._radiusDown[1]));
         dist = dist < 3 ? 0 : dist;
-        let usingRule = false;
-        SelectionManager.SelectedDocuments().map(dv => {
-            const ruleProvider = dv.props.ruleProvider;
-            const heading = NumCast(dv.props.Document.heading);
-            ruleProvider && heading && (Doc.GetProto(ruleProvider)["ruleRounding_" + heading] = `${Math.min(100, dist)}%`);
-            usingRule = usingRule || (ruleProvider && heading ? true : false);
-        });
-        !usingRule && SelectionManager.SelectedDocuments().map(dv => dv.props.Document.layout instanceof Doc ? dv.props.Document.layout : dv.props.Document.isTemplateForField ? dv.props.Document : Doc.GetProto(dv.props.Document)).
+        SelectionManager.SelectedDocuments().map(dv => dv.props.Document.layout instanceof Doc ? dv.props.Document.layout : dv.props.Document.isTemplateForField ? dv.props.Document : Doc.GetProto(dv.props.Document)).
             map(d => d.borderRounding = `${Math.min(100, dist)}%`);
         e.stopPropagation();
         e.preventDefault();
diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index 84d089b47..580c53a37 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -462,7 +462,6 @@ export default class GestureOverlay extends Touchable {
                 addDocTab={returnFalse}
                 pinToPres={emptyFunction}
                 onClick={undefined}
-                ruleProvider={undefined}
                 removeDocument={undefined}
                 ScreenToLocalTransform={() => new Transform(-(this._thumbX ?? 0), -(this._thumbY ?? 0) + this.height, 1)}
                 ContentScaling={returnOne}
diff --git a/src/client/views/InkingControl.tsx b/src/client/views/InkingControl.tsx
index ab53b76be..10d013865 100644
--- a/src/client/views/InkingControl.tsx
+++ b/src/client/views/InkingControl.tsx
@@ -55,34 +55,7 @@ export class InkingControl {
                 }
                 const oldColor = StrCast(targetDoc.backgroundColor);
                 let matchedColor = this._selectedColor;
-                const cvd = view.props.ContainingCollectionDoc;
-                let ruleProvider = view.props.ruleProvider;
-                // if (cvd) {
-                //     if (!cvd.colorPalette) {
-                //         const defaultPalette = ["rg(114,229,239)", "rgb(255,246,209)", "rgb(255,188,156)", "rgb(247,220,96)", "rgb(122,176,238)",
-                //             "rgb(209,150,226)", "rgb(127,235,144)", "rgb(252,188,189)", "rgb(247,175,81)",];
-                //         const colorPalette = Cast(cvd.colorPalette, listSpec("string"));
-                //         if (!colorPalette) cvd.colorPalette = new List<string>(defaultPalette);
-                //     }
-                //     const cp = Cast(cvd.colorPalette, listSpec("string")) as string[];
-                //     let closest = 0;
-                //     let dist = 10000000;
-                //     const ccol = Utils.fromRGBAstr(StrCast(targetDoc.backgroundColor));
-                //     for (let i = 0; i < cp.length; i++) {
-                //         const cpcol = Utils.fromRGBAstr(cp[i]);
-                //         const d = Math.sqrt((ccol.r - cpcol.r) * (ccol.r - cpcol.r) + (ccol.b - cpcol.b) * (ccol.b - cpcol.b) + (ccol.g - cpcol.g) * (ccol.g - cpcol.g));
-                //         if (d < dist) {
-                //             dist = d;
-                //             closest = i;
-                //         }
-                //     }
-                //     cp[closest] = "rgba(" + color.rgb.r + "," + color.rgb.g + "," + color.rgb.b + "," + color.rgb.a + ")";
-                //     cvd.colorPalette = new List(cp);
-                //     matchedColor = cp[closest];
-                //     ruleProvider = (view.props.Document.heading && ruleProvider) ? ruleProvider : undefined;
-                //     ruleProvider && ((Doc.GetProto(ruleProvider)["ruleColor_" + NumCast(view.props.Document.heading)] = Utils.toRGBAstr(color.rgb)));
-                // }
-                (!ruleProvider && targetDoc) && (Doc.Layout(view.props.Document).backgroundColor = matchedColor);
+                targetDoc && (Doc.Layout(view.props.Document).backgroundColor = matchedColor);
 
                 return {
                     target: targetDoc,
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 79e0cfea5..cd4e9a1a6 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -276,7 +276,6 @@ export class MainView extends React.Component {
             addDocTab={this.addDocTabFunc}
             pinToPres={emptyFunction}
             onClick={undefined}
-            ruleProvider={undefined}
             removeDocument={undefined}
             ScreenToLocalTransform={Transform.Identity}
             ContentScaling={returnOne}
@@ -377,7 +376,6 @@ export class MainView extends React.Component {
                     addDocTab={this.addDocTabFunc}
                     pinToPres={emptyFunction}
                     removeDocument={undefined}
-                    ruleProvider={undefined}
                     onClick={undefined}
                     ScreenToLocalTransform={Transform.Identity}
                     ContentScaling={returnOne}
@@ -404,7 +402,6 @@ export class MainView extends React.Component {
                     addDocTab={this.addDocTabFunc}
                     pinToPres={emptyFunction}
                     removeDocument={returnFalse}
-                    ruleProvider={undefined}
                     onClick={undefined}
                     ScreenToLocalTransform={this.mainContainerXf}
                     ContentScaling={returnOne}
@@ -500,7 +497,6 @@ export class MainView extends React.Component {
                     addDocTab={this.addDocTabFunc}
                     pinToPres={emptyFunction}
                     removeDocument={this.remButtonDoc}
-                    ruleProvider={undefined}
                     onClick={undefined}
                     ScreenToLocalTransform={this.buttonBarXf}
                     ContentScaling={returnOne}
diff --git a/src/client/views/OverlayView.tsx b/src/client/views/OverlayView.tsx
index 350a75d29..295cd7c6e 100644
--- a/src/client/views/OverlayView.tsx
+++ b/src/client/views/OverlayView.tsx
@@ -178,7 +178,6 @@ export class OverlayView extends React.Component {
                     // select={emptyFunction}
                     // layoutKey={"layout"}
                     bringToFront={emptyFunction}
-                    ruleProvider={undefined}
                     addDocument={undefined}
                     removeDocument={undefined}
                     ContentScaling={returnOne}
diff --git a/src/client/views/Palette.tsx b/src/client/views/Palette.tsx
index 811c24f53..10aac96a0 100644
--- a/src/client/views/Palette.tsx
+++ b/src/client/views/Palette.tsx
@@ -56,7 +56,6 @@ export default class Palette extends React.Component<PaletteProps> {
                             addDocTab={returnFalse}
                             pinToPres={emptyFunction}
                             removeDocument={undefined}
-                            ruleProvider={undefined}
                             onClick={undefined}
                             ScreenToLocalTransform={Transform.Identity}
                             ContentScaling={returnOne}
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 5f9b4e0c7..125cd828f 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -723,7 +723,6 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
             bringToFront={emptyFunction}
             addDocument={undefined}
             removeDocument={undefined}
-            ruleProvider={undefined}
             ContentScaling={this.contentScaling}
             PanelWidth={this.panelWidth}
             PanelHeight={this.panelHeight}
diff --git a/src/client/views/collections/CollectionLinearView.tsx b/src/client/views/collections/CollectionLinearView.tsx
index 77af2dc0e..8bf6b4202 100644
--- a/src/client/views/collections/CollectionLinearView.tsx
+++ b/src/client/views/collections/CollectionLinearView.tsx
@@ -108,7 +108,6 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) {
                                 addDocTab={this.props.addDocTab}
                                 pinToPres={emptyFunction}
                                 removeDocument={this.props.removeDocument}
-                                ruleProvider={undefined}
                                 onClick={undefined}
                                 ScreenToLocalTransform={this.getTransform(dref)}
                                 ContentScaling={returnOne}
diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx
index 79a34bc00..7e990ab4d 100644
--- a/src/client/views/collections/CollectionSchemaCells.tsx
+++ b/src/client/views/collections/CollectionSchemaCells.tsx
@@ -145,7 +145,6 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
             DataDoc: this.props.rowProps.original,
             LibraryPath: [],
             fieldKey: this.props.rowProps.column.id as string,
-            ruleProvider: undefined,
             ContainingCollectionView: this.props.CollectionView,
             ContainingCollectionDoc: this.props.CollectionView && this.props.CollectionView.props.Document,
             isSelected: returnFalse,
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index b466d9511..994c7b351 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -144,7 +144,6 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
                 LibraryPath={this.props.LibraryPath}
                 childDocs={this.childDocs}
                 renderDepth={this.props.renderDepth}
-                ruleProvider={this.props.Document.isRuleProvider && layoutDoc && layoutDoc.type !== DocumentType.TEXT ? this.props.Document : this.props.ruleProvider}
                 PanelWidth={this.previewWidth}
                 PanelHeight={this.previewHeight}
                 getTransform={this.getPreviewTransform}
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index b2e4b9d90..ec22bb813 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -39,7 +39,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
     @observable _scroll = 0; // used to force the document decoration to update when scrolling
     @computed get sectionHeaders() { return Cast(this.props.Document.sectionHeaders, listSpec(SchemaHeaderField)); }
     @computed get sectionFilter() { return StrCast(this.props.Document.sectionFilter); }
-    @computed get filteredChildren() { return this.childDocs.filter(d => !d.isMinimized).map(d => (Doc.GetLayoutDataDocPair(this.props.Document, this.props.DataDoc, d).layout as Doc) || d); }
+    @computed get filteredChildren() { return this.childLayoutPairs.filter(pair => !pair.layout.isMinimized).map(pair => pair.layout); }
     @computed get xMargin() { return NumCast(this.props.Document.xMargin, 2 * this.gridGap); }
     @computed get yMargin() { return Math.max(this.props.Document.showTitle && !this.props.Document.showTitleHover ? 30 : 0, NumCast(this.props.Document.yMargin, 2 * this.gridGap)); }
     @computed get gridGap() { return NumCast(this.props.Document.gridGap, 10); }
@@ -167,7 +167,6 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
             LibraryPath={this.props.LibraryPath}
             showOverlays={this.overlays}
             renderDepth={this.props.renderDepth + 1}
-            ruleProvider={this.props.Document.isRuleProvider && layoutDoc.type !== DocumentType.TEXT ? this.props.Document : this.props.ruleProvider}
             fitToBox={this.props.fitToBox}
             onClick={layoutDoc.isTemplateDoc ? this.onClickHandler : this.onChildClickHandler}
             PanelWidth={width}
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 6c4f940b6..063b5c5df 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -40,7 +40,6 @@ export interface CollectionViewProps extends FieldViewProps {
 
 export interface SubCollectionViewProps extends CollectionViewProps {
     CollectionView: Opt<CollectionView>;
-    ruleProvider: Doc | undefined;
     children?: never | (() => JSX.Element[]) | React.ReactNode;
     isAnnotationOverlay?: boolean;
     annotationsKey: string;
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 2c8c53f97..ec348e74b 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -43,7 +43,6 @@ export interface TreeViewProps {
     prevSibling?: Doc;
     renderDepth: number;
     deleteDoc: (doc: Doc) => boolean;
-    ruleProvider: Doc | undefined;
     moveDocument: DragManager.MoveFunction;
     dropAction: "alias" | "copy" | undefined;
     addDocTab: (doc: Doc, dataDoc: Doc | undefined, where: string, libraryPath?: Doc[]) => boolean;
@@ -352,7 +351,6 @@ class TreeView extends React.Component<TreeViewProps> {
                     LibraryPath={emptyPath}
                     renderDepth={this.props.renderDepth + 1}
                     showOverlays={this.noOverlays}
-                    ruleProvider={this.props.document.isRuleProvider && layoutDoc.type !== DocumentType.TEXT ? this.props.document : this.props.ruleProvider}
                     fitToBox={this.boundsOfCollectionDocument !== undefined}
                     PanelWidth={this.docWidth}
                     PanelHeight={this.docHeight}
@@ -559,7 +557,6 @@ class TreeView extends React.Component<TreeViewProps> {
                 containingCollection={containingCollection}
                 prevSibling={docs[i]}
                 treeViewId={treeViewId}
-                ruleProvider={containingCollection.isRuleProvider && pair.layout.type !== DocumentType.TEXT ? containingCollection : containingCollection.ruleProvider as Doc}
                 key={child[Id]}
                 indentDocument={indent}
                 outdentDocument={outdent}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index aa1559416..65953dbdc 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -54,7 +54,6 @@ export const panZoomSchema = createSchema({
     arrangeScript: ScriptField,
     arrangeInit: ScriptField,
     useClusters: "boolean",
-    isRuleProvider: "boolean",
     fitToBox: "boolean",
     xPadding: "number",         // pixels of padding on left/right of collectionfreeformview contents when fitToBox is set
     yPadding: "number",         // pixels of padding on left/right of collectionfreeformview contents when fitToBox is set
@@ -103,14 +102,6 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
     private getLocalTransform = (): Transform => Transform.Identity().scale(1 / this.zoomScaling()).translate(this.panX(), this.panY());
     private addLiveTextBox = (newBox: Doc) => {
         FormattedTextBox.SelectOnLoad = newBox[Id];// track the new text box so we can give it a prop that tells it to focus itself when it's displayed
-        const maxHeading = this.childDocs.reduce((maxHeading, doc) => NumCast(doc.heading) > maxHeading ? NumCast(doc.heading) : maxHeading, 0);
-        let heading = maxHeading === 0 || this.childDocs.length === 0 ? 1 : maxHeading === 1 ? 2 : 0;
-        if (heading === 0) {
-            const sorted = this.childDocs.filter(d => d.type === DocumentType.TEXT && d.data_ext instanceof Doc && d.data_ext.lastModified).sort((a, b) => DateCast((Cast(a.data_ext, Doc) as Doc).lastModified).date > DateCast((Cast(b.data_ext, Doc) as Doc).lastModified).date ? 1 :
-                DateCast((Cast(a.data_ext, Doc) as Doc).lastModified).date < DateCast((Cast(b.data_ext, Doc) as Doc).lastModified).date ? -1 : 0);
-            heading = !sorted.length ? Math.max(1, maxHeading) : NumCast(sorted[sorted.length - 1].heading) === 1 ? 2 : NumCast(sorted[sorted.length - 1].heading);
-        }
-        !this.Document.isRuleProvider && (newBox.heading = heading);
         this.addDocument(newBox);
     }
     private addDocument = (newBox: Doc) => {
@@ -412,16 +403,16 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
         const [dx, dy] = this.getTransform().transformDirection(e.clientX - this._lastX, e.clientY - this._lastY);
         if (!this.isAnnotationOverlay) {
             PDFMenu.Instance.fadeOut(true);
-            const minx = docs.length ? NumCast(docs[0].x) : 0;
-            const maxx = docs.length ? NumCast(docs[0].width) + minx : minx;
-            const miny = docs.length ? NumCast(docs[0].y) : 0;
-            const maxy = docs.length ? NumCast(docs[0].height) + miny : miny;
+            const minx = this.childDataProvider(docs[0]).x;//docs.length ? NumCast(docs[0].x) : 0;
+            const miny = this.childDataProvider(docs[0]).y;//docs.length ? NumCast(docs[0].y) : 0;
+            const maxx = this.childDataProvider(docs[0]).width + minx;//docs.length ? NumCast(docs[0].width) + minx : minx;
+            const maxy = this.childDataProvider(docs[0]).height + miny;//docs.length ? NumCast(docs[0].height) + miny : miny;
             const ranges = docs.filter(doc => doc).reduce((range, doc) => {
                 const layoutDoc = Doc.Layout(doc);
-                const x = NumCast(doc.x);
-                const xe = x + NumCast(layoutDoc.width);
-                const y = NumCast(doc.y);
-                const ye = y + NumCast(layoutDoc.height);
+                const x = this.childDataProvider(doc).x;//NumCast(doc.x);
+                const y = this.childDataProvider(doc).y;//NumCast(doc.y);
+                const xe = this.childDataProvider(doc).width + x;//x + NumCast(layoutDoc.width);
+                const ye = this.childDataProvider(doc).height + y; //y + NumCast(layoutDoc.height);
                 return [[range[0][0] > x ? x : range[0][0], range[0][1] < xe ? xe : range[0][1]],
                 [range[1][0] > y ? y : range[1][0], range[1][1] < ye ? ye : range[1][1]]];
             }, [[minx, maxx], [miny, maxy]]);
@@ -694,7 +685,6 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
             Document: childLayout,
             LibraryPath: this.libraryPath,
             layoutKey: undefined,
-            ruleProvider: this.Document.isRuleProvider && childLayout.type !== DocumentType.TEXT ? this.props.Document : this.props.ruleProvider, //bcz: hack! - currently ruleProviders apply to documents in nested colleciton, not direct children of themselves
             //onClick: undefined, // this.props.onClick,  // bcz: check this out -- I don't think we want to inherit click handlers, or we at least need a way to ignore them
             onClick: this.onChildClickHandler,
             ScreenToLocalTransform: childLayout.z ? this.getTransformOverlay : this.getTransform,
@@ -779,7 +769,6 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
             computedElementData.elements.push({
                 ele: <CollectionFreeFormDocumentView key={pair.layout[Id]}  {...this.getChildDocumentViewProps(pair.layout, pair.data)}
                     dataProvider={this.childDataProvider}
-                    ruleProvider={this.Document.isRuleProvider ? this.props.Document : this.props.ruleProvider}
                     jitterRotation={NumCast(this.props.Document.jitterRotation)}
                     fitToBox={this.props.fitToBox || this.Document.freeformLayoutEngine === "pivot"} />,
                 bounds: this.childDataProvider(pair.layout)
@@ -827,20 +816,6 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
         }, "arrange contents");
     }
 
-    autoFormat = () => {
-        this.Document.isRuleProvider = !this.Document.isRuleProvider;
-        // find rule colorations when rule providing is turned on by looking at each document to see if it has a coloring -- if so, use it's color as the rule for its associated heading.
-        this.Document.isRuleProvider && this.childLayoutPairs.map(pair =>
-            // iterate over the children of a displayed document (or if the displayed document is a template, iterate over the children of that template)
-            DocListCast(Doc.Layout(pair.layout).data).map(heading => {
-                const headingPair = Doc.GetLayoutDataDocPair(this.props.Document, this.props.DataDoc, heading);
-                const headingLayout = headingPair.layout && (pair.layout.data_ext instanceof Doc) && (pair.layout.data_ext[`Layout[${headingPair.layout[Id]}]`] as Doc) || headingPair.layout;
-                if (headingLayout && NumCast(headingLayout.heading) > 0 && headingLayout.backgroundColor !== headingLayout.defaultBackgroundColor) {
-                    Doc.GetProto(this.props.Document)["ruleColor_" + NumCast(headingLayout.heading)] = headingLayout.backgroundColor;
-                }
-            })
-        );
-    }
 
     analyzeStrokes = async () => {
         const children = await DocListCastAsync(this.dataDoc.data);
@@ -908,7 +883,6 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
         layoutItems.push({ description: `${this.Document.LODdisable ? "Enable LOD" : "Disable LOD"}`, event: () => this.Document.LODdisable = !this.Document.LODdisable, icon: "table" });
         layoutItems.push({ description: `${this.fitToContent ? "Unset" : "Set"} Fit To Container`, event: () => this.Document.fitToBox = !this.fitToContent, icon: !this.fitToContent ? "expand-arrows-alt" : "compress-arrows-alt" });
         layoutItems.push({ description: `${this.Document.useClusters ? "Uncluster" : "Use Clusters"}`, event: () => this.updateClusters(!this.Document.useClusters), icon: "braille" });
-        layoutItems.push({ description: `${this.Document.isRuleProvider ? "Stop Auto Format" : "Auto Format"}`, event: this.autoFormat, icon: "chalkboard" });
         layoutItems.push({ description: "Arrange contents in grid", event: this.layoutDocsInGrid, icon: "table" });
         layoutItems.push({ description: "Analyze Strokes", event: this.analyzeStrokes, icon: "paint-brush" });
         layoutItems.push({ description: "Jitter Rotation", event: action(() => this.props.Document.jitterRotation = 10), icon: "paint-brush" });
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index 614a68e7a..cd78f5d49 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -73,10 +73,8 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
         .scale(1 / this.contentScaling())
 
     borderRounding = () => {
-        const ruleRounding = this.props.ruleProvider ? StrCast(this.props.ruleProvider["ruleRounding_" + this.Document.heading]) : undefined;
         const ld = this.layoutDoc[StrCast(this.layoutDoc.layoutKey, "layout")] instanceof Doc ? this.layoutDoc[StrCast(this.layoutDoc.layoutKey, "layout")] as Doc : undefined;
-        const br = StrCast((ld || this.props.Document).borderRounding);
-        return !br && ruleRounding ? ruleRounding : br;
+        return StrCast((ld || this.props.Document).borderRounding);
     }
 
     @computed
diff --git a/src/client/views/nodes/ContentFittingDocumentView.tsx b/src/client/views/nodes/ContentFittingDocumentView.tsx
index e97445f27..96102e0e8 100644
--- a/src/client/views/nodes/ContentFittingDocumentView.tsx
+++ b/src/client/views/nodes/ContentFittingDocumentView.tsx
@@ -24,7 +24,6 @@ interface ContentFittingDocumentViewProps {
     fitToBox?: boolean;
     PanelWidth: () => number;
     PanelHeight: () => number;
-    ruleProvider: Doc | undefined;
     focus?: (doc: Doc) => void;
     showOverlays?: (doc: Doc) => { title?: string, caption?: string };
     CollectionView?: CollectionView;
@@ -97,7 +96,6 @@ export class ContentFittingDocumentView extends React.Component<ContentFittingDo
                         LibraryPath={this.props.LibraryPath}
                         fitToBox={this.props.fitToBox}
                         onClick={this.props.onClick}
-                        ruleProvider={this.props.ruleProvider}
                         showOverlays={this.props.showOverlays}
                         addDocument={this.props.addDocument}
                         removeDocument={this.props.removeDocument}
diff --git a/src/client/views/nodes/DocumentBox.tsx b/src/client/views/nodes/DocumentBox.tsx
index 863ea748b..6b7b652c6 100644
--- a/src/client/views/nodes/DocumentBox.tsx
+++ b/src/client/views/nodes/DocumentBox.tsx
@@ -96,7 +96,6 @@ export class DocumentBox extends DocComponent<FieldViewProps, DocBoxSchema>(DocB
                 addDocument={this.props.addDocument}
                 moveDocument={this.props.moveDocument}
                 removeDocument={this.props.removeDocument}
-                ruleProvider={this.props.ruleProvider}
                 addDocTab={this.props.addDocTab}
                 pinToPres={this.props.pinToPres}
                 getTransform={this.getTransform}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index b491acb8d..2570d232a 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -72,7 +72,6 @@ export interface DocumentViewProps {
     renderDepth: number;
     showOverlays?: (doc: Doc) => { title?: string, titleHover?: string, caption?: string };
     ContentScaling: () => number;
-    ruleProvider: Doc | undefined;
     PanelWidth: () => number;
     PanelHeight: () => number;
     focus: (doc: Doc, willZoom: boolean, scale?: number, afterFocus?: () => boolean) => void;
@@ -875,7 +874,6 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
             renderDepth={this.props.renderDepth}
             showOverlays={this.props.showOverlays}
             ContentScaling={this.childScaling}
-            ruleProvider={this.props.ruleProvider}
             PanelWidth={this.props.PanelWidth}
             PanelHeight={this.props.PanelHeight}
             focus={this.props.focus}
@@ -967,16 +965,14 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
 
     render() {
         if (!(this.props.Document instanceof Doc)) return (null);
-        const ruleColor = this.props.ruleProvider ? StrCast(this.props.ruleProvider["ruleColor_" + this.Document.heading]) : undefined;
-        const ruleRounding = this.props.ruleProvider ? StrCast(this.props.ruleProvider["ruleRounding_" + this.Document.heading]) : undefined;
         const colorSet = this.setsLayoutProp("backgroundColor");
         const clusterCol = this.props.ContainingCollectionDoc && this.props.ContainingCollectionDoc.clusterOverridesDefaultBackground;
         const backgroundColor = (clusterCol && !colorSet) ?
             this.props.backgroundColor(this.Document) || StrCast(this.layoutDoc.backgroundColor) :
-            ruleColor && !colorSet ? ruleColor : StrCast(this.layoutDoc.backgroundColor) || this.props.backgroundColor(this.Document);
+            StrCast(this.layoutDoc.backgroundColor) || this.props.backgroundColor(this.Document);
 
         const fullDegree = Doc.isBrushedHighlightedDegree(this.props.Document);
-        const borderRounding = this.getLayoutPropStr("borderRounding") || ruleRounding;
+        const borderRounding = this.getLayoutPropStr("borderRounding");
         const localScale = fullDegree;
 
         const animDims = this.Document.animateToDimensions ? Array.from(this.Document.animateToDimensions) : undefined;
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index 6e6ee1712..538e433a9 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -27,7 +27,6 @@ export interface FieldViewProps {
     fitToBox?: boolean;
     ContainingCollectionView: Opt<CollectionView>;
     ContainingCollectionDoc: Opt<Doc>;
-    ruleProvider: Doc | undefined;
     Document: Doc;
     DataDoc?: Doc;
     LibraryPath: Doc[];
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 3814f02da..0a1a79bc4 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -89,7 +89,6 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
     private _scrollToRegionReactionDisposer: Opt<IReactionDisposer>;
     private _reactionDisposer: Opt<IReactionDisposer>;
     private _heightReactionDisposer: Opt<IReactionDisposer>;
-    private _rulesReactionDisposer: Opt<IReactionDisposer>;
     private _proxyReactionDisposer: Opt<IReactionDisposer>;
     private _pullReactionDisposer: Opt<IReactionDisposer>;
     private _pushReactionDisposer: Opt<IReactionDisposer>;
@@ -549,36 +548,6 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
             search => search ? this.highlightSearchTerms([Doc.SearchQuery()]) : this.unhighlightSearchTerms(),
             { fireImmediately: true });
 
-        this._rulesReactionDisposer = reaction(() => {
-            const ruleProvider = this.props.ruleProvider;
-            const heading = NumCast(this.layoutDoc.heading);
-            if (ruleProvider instanceof Doc) {
-                return {
-                    align: StrCast(ruleProvider["ruleAlign_" + heading], ""),
-                    font: StrCast(ruleProvider["ruleFont_" + heading], "Arial"),
-                    size: NumCast(ruleProvider["ruleSize_" + heading], 13)
-                };
-            }
-            return undefined;
-        },
-            action((rules: any) => {
-                this._ruleFontFamily = rules ? rules.font : "Arial";
-                this._ruleFontSize = rules ? rules.size : 0;
-                rules && setTimeout(() => {
-                    const view = this._editorView!;
-                    if (this.ProseRef) {
-                        const n = new NodeSelection(view.state.doc.resolve(0));
-                        if (this._editorView!.state.doc.textContent === "") {
-                            view.dispatch(view.state.tr.setSelection(new TextSelection(view.state.doc.resolve(0), view.state.doc.resolve(2))).
-                                replaceSelectionWith(this._editorView!.state.schema.nodes.paragraph.create({ align: rules.align }), true));
-                        } else if (n.node && n.node.type === view.state.schema.nodes.paragraph) {
-                            view.dispatch(view.state.tr.setNodeMarkup(0, n.node.type, { ...n.node.attrs, align: rules.align }));
-                        }
-                        this.tryUpdateHeight();
-                    }
-                }, 0);
-            }), { fireImmediately: true }
-        );
         this._scrollToRegionReactionDisposer = reaction(
             () => StrCast(this.layoutDoc.scrollToLinkID),
             async (scrollToLinkID) => {
@@ -849,7 +818,6 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
 
     componentWillUnmount() {
         this._scrollToRegionReactionDisposer && this._scrollToRegionReactionDisposer();
-        this._rulesReactionDisposer && this._rulesReactionDisposer();
         this._reactionDisposer && this._reactionDisposer();
         this._proxyReactionDisposer && this._proxyReactionDisposer();
         this._pushReactionDisposer && this._pushReactionDisposer();
@@ -1171,7 +1139,6 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
                             addDocument={(doc: Doc) => { doc.hideSidebar = true; return this.addDocument(doc); }}
                             CollectionView={undefined}
                             ScreenToLocalTransform={() => this.props.ScreenToLocalTransform().translate(-(this.props.PanelWidth() - this.sidebarWidth), 0)}
-                            ruleProvider={undefined}
                             renderDepth={this.props.renderDepth + 1}
                             ContainingCollectionDoc={this.props.ContainingCollectionDoc}
                             chromeCollapsed={true}>
diff --git a/src/client/views/nodes/FormattedTextBoxComment.tsx b/src/client/views/nodes/FormattedTextBoxComment.tsx
index f7a530790..8dedfda9b 100644
--- a/src/client/views/nodes/FormattedTextBoxComment.tsx
+++ b/src/client/views/nodes/FormattedTextBoxComment.tsx
@@ -185,7 +185,6 @@ export class FormattedTextBoxComment {
                                     active={returnFalse}
                                     addDocument={returnFalse}
                                     removeDocument={returnFalse}
-                                    ruleProvider={undefined}
                                     addDocTab={returnFalse}
                                     pinToPres={returnFalse}
                                     dontRegisterView={true}
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index db427710e..b7e904283 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -364,7 +364,6 @@ export class ImageBox extends DocAnnotatableComponent<FieldViewProps, ImageDocum
                 addDocument={this.addDocument}
                 CollectionView={undefined}
                 ScreenToLocalTransform={this.props.ScreenToLocalTransform}
-                ruleProvider={undefined}
                 renderDepth={this.props.renderDepth + 1}
                 ContainingCollectionDoc={this.props.ContainingCollectionDoc}
                 chromeCollapsed={true}>
diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx
index 91f8bb3b0..46466aa0f 100644
--- a/src/client/views/nodes/KeyValuePair.tsx
+++ b/src/client/views/nodes/KeyValuePair.tsx
@@ -58,7 +58,6 @@ export class KeyValuePair extends React.Component<KeyValuePairProps> {
             LibraryPath: [],
             ContainingCollectionView: undefined,
             ContainingCollectionDoc: undefined,
-            ruleProvider: undefined,
             fieldKey: this.props.keyName,
             isSelected: returnFalse,
             select: emptyFunction,
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index 376d27380..52b4f391a 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -353,7 +353,6 @@ export class VideoBox extends DocAnnotatableComponent<FieldViewProps, VideoDocum
                     addDocument={this.addDocumentWithTimestamp}
                     CollectionView={undefined}
                     ScreenToLocalTransform={this.props.ScreenToLocalTransform}
-                    ruleProvider={undefined}
                     renderDepth={this.props.renderDepth + 1}
                     ContainingCollectionDoc={this.props.ContainingCollectionDoc}
                     chromeCollapsed={true}>
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index e9118e3ab..f21f9ff46 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -211,7 +211,6 @@ export class WebBox extends DocAnnotatableComponent<FieldViewProps, WebDocument>
                 addDocument={this.addDocument}
                 CollectionView={undefined}
                 ScreenToLocalTransform={this.props.ScreenToLocalTransform}
-                ruleProvider={undefined}
                 renderDepth={this.props.renderDepth + 1}
                 ContainingCollectionDoc={this.props.ContainingCollectionDoc}
                 chromeCollapsed={true}>
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 62467ce4d..d6829937e 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -650,7 +650,6 @@ export class PDFViewer extends DocAnnotatableComponent<IViewerProps, PdfDocument
                 addDocument={this.addDocument}
                 CollectionView={undefined}
                 ScreenToLocalTransform={this.overlayTransform}
-                ruleProvider={undefined}
                 renderDepth={this.props.renderDepth + 1}
                 ContainingCollectionDoc={this.props.ContainingCollectionView?.props.Document}
                 chromeCollapsed={true}>
diff --git a/src/client/views/presentationview/PresElementBox.tsx b/src/client/views/presentationview/PresElementBox.tsx
index c02042380..92dc0f3d2 100644
--- a/src/client/views/presentationview/PresElementBox.tsx
+++ b/src/client/views/presentationview/PresElementBox.tsx
@@ -175,7 +175,6 @@ export class PresElementBox extends DocComponent<FieldViewProps, PresDocument>(P
                     fitToBox={StrCast(this.targetDoc.type).indexOf(DocumentType.COL) !== -1}
                     addDocument={returnFalse}
                     removeDocument={returnFalse}
-                    ruleProvider={undefined}
                     addDocTab={returnFalse}
                     pinToPres={returnFalse}
                     PanelWidth={() => this.props.PanelWidth() - 20}
diff --git a/src/client/views/search/SearchItem.tsx b/src/client/views/search/SearchItem.tsx
index 30fcc7908..21a4560cf 100644
--- a/src/client/views/search/SearchItem.tsx
+++ b/src/client/views/search/SearchItem.tsx
@@ -161,7 +161,6 @@ export class SearchItem extends React.Component<SearchItemProps> {
                     fitToBox={StrCast(this.props.doc.type).indexOf(DocumentType.COL) !== -1}
                     addDocument={returnFalse}
                     removeDocument={returnFalse}
-                    ruleProvider={undefined}
                     addDocTab={returnFalse}
                     pinToPres={returnFalse}
                     getTransform={Transform.Identity}
diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx
index ea2fc917f..b1eaeaa0a 100644
--- a/src/mobile/MobileInterface.tsx
+++ b/src/mobile/MobileInterface.tsx
@@ -38,7 +38,6 @@ export default class MobileInterface extends React.Component {
                 addDocTab={returnFalse}
                 pinToPres={emptyFunction}
                 removeDocument={undefined}
-                ruleProvider={undefined}
                 onClick={undefined}
                 ScreenToLocalTransform={Transform.Identity}
                 ContentScaling={returnOne}
-- 
cgit v1.2.3-70-g09d2


From e4a9b55c40dffd9a9add9e814e3ce4611e2a318e Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Fri, 24 Jan 2020 18:12:05 -0500
Subject: fixed color setting from colorbox.

---
 package-lock.json                  | 10 ++++++++++
 src/client/views/InkingControl.tsx | 33 +++++----------------------------
 2 files changed, 15 insertions(+), 28 deletions(-)

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

diff --git a/package-lock.json b/package-lock.json
index fe1007c68..5d98a78a1 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -4637,6 +4637,7 @@
                 "map-stream": "0.0.7",
                 "pause-stream": "0.0.11",
                 "split": "1.0.1",
+                "stream-combiner": "0.2.2",
                 "through": "2.3.8"
             }
         },
@@ -15547,6 +15548,15 @@
                 "readable-stream": "2.3.6"
             }
         },
+        "stream-combiner": {
+            "version": "0.2.2",
+            "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.2.2.tgz",
+            "integrity": "sha1-rsjLrBd7Vrb0+kec7YwZEs7lKFg=",
+            "requires": {
+                "duplexer": "0.1.1",
+                "through": "2.3.8"
+            }
+        },
         "stream-each": {
             "version": "1.2.3",
             "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz",
diff --git a/src/client/views/InkingControl.tsx b/src/client/views/InkingControl.tsx
index 10d013865..6cee702ee 100644
--- a/src/client/views/InkingControl.tsx
+++ b/src/client/views/InkingControl.tsx
@@ -2,14 +2,11 @@ import { action, computed, observable } from "mobx";
 import { ColorState } from 'react-color';
 import { Doc } from "../../new_fields/Doc";
 import { InkTool } from "../../new_fields/InkField";
-import { List } from "../../new_fields/List";
-import { listSpec } from "../../new_fields/Schema";
-import { Cast, NumCast, StrCast, FieldValue } from "../../new_fields/Types";
-import { Utils } from "../../Utils";
+import { FieldValue, NumCast, StrCast } from "../../new_fields/Types";
+import { CurrentUserUtils } from "../../server/authentication/models/current_user_utils";
 import { Scripting } from "../util/Scripting";
 import { SelectionManager } from "../util/SelectionManager";
-import { undoBatch, UndoManager } from "../util/UndoManager";
-import { CurrentUserUtils } from "../../server/authentication/models/current_user_utils";
+import { undoBatch } from "../util/UndoManager";
 import GestureOverlay from "./GestureOverlay";
 
 export class InkingControl {
@@ -41,32 +38,12 @@ export class InkingControl {
 
         if (InkingControl.Instance.selectedTool === InkTool.None) {
             const selected = SelectionManager.SelectedDocuments();
-            const oldColors = selected.map(view => {
+            selected.map(view => {
                 const targetDoc = view.props.Document.dragFactory instanceof Doc ? view.props.Document.dragFactory :
                     view.props.Document.layout instanceof Doc ? view.props.Document.layout :
                         view.props.Document.isTemplateForField ? view.props.Document : Doc.GetProto(view.props.Document);
-                const sel = window.getSelection();
-                if (StrCast(targetDoc.layout).indexOf("FormattedTextBox") !== -1 && (!sel || sel.toString() !== "")) {
-                    targetDoc.color = this._selectedColor;
-                    return {
-                        target: targetDoc,
-                        previous: StrCast(targetDoc.color)
-                    };
-                }
-                const oldColor = StrCast(targetDoc.backgroundColor);
-                let matchedColor = this._selectedColor;
-                targetDoc && (Doc.Layout(view.props.Document).backgroundColor = matchedColor);
-
-                return {
-                    target: targetDoc,
-                    previous: oldColor
-                };
+                targetDoc && (Doc.Layout(view.props.Document).backgroundColor = CurrentUserUtils.UserDocument.inkColor);
             });
-            //let captured = this._selectedColor;
-            // UndoManager.AddEvent({
-            //     undo: () => oldColors.forEach(pair => pair.target.backgroundColor = pair.previous),
-            //     redo: () => oldColors.forEach(pair => pair.target.backgroundColor = captured)
-            // });
         } else {
             CurrentUserUtils.ActivePen && (CurrentUserUtils.ActivePen.backgroundColor = this._selectedColor);
         }
-- 
cgit v1.2.3-70-g09d2

