From 17cab0166753aee765585e1eb700fd85583e7cbb Mon Sep 17 00:00:00 2001
From: monikahedman <monika_hedman@brown.edu>
Date: Mon, 5 Aug 2019 19:11:54 -0400
Subject: clickable text box appears

---
 src/client/views/nodes/FormattedTextBox.tsx | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

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

diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index e076efe18..a2e610fc2 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -8,7 +8,7 @@ import { keymap } from "prosemirror-keymap";
 import { Node as ProsNode } from "prosemirror-model";
 import { EditorState, Plugin, Transaction, Selection } from "prosemirror-state";
 import { NodeType, Slice, Node, Fragment } from 'prosemirror-model';
-import { EditorView } from "prosemirror-view";
+import { EditorView, NodeView } from "prosemirror-view";
 import { Doc, Opt, DocListCast } from "../../../new_fields/Doc";
 import { Id, Copy } from '../../../new_fields/FieldSymbols';
 import { List } from '../../../new_fields/List';
@@ -21,7 +21,7 @@ import { DocumentManager } from '../../util/DocumentManager';
 import { DragManager } from "../../util/DragManager";
 import buildKeymap from "../../util/ProsemirrorExampleTransfer";
 import { inpRules } from "../../util/RichTextRules";
-import { ImageResizeView, schema, SummarizedView } from "../../util/RichTextSchema";
+import { ImageResizeView, schema, SummarizedView, CheckboxView } from "../../util/RichTextSchema";
 import { SelectionManager } from "../../util/SelectionManager";
 import { TooltipLinkingMenu } from "../../util/TooltipLinkingMenu";
 import { TooltipTextMenu } from "../../util/TooltipTextMenu";
@@ -38,6 +38,7 @@ import { For } from 'babel-types';
 import { DateField } from '../../../new_fields/DateField';
 import { Utils } from '../../../Utils';
 import { MainOverlayTextBox } from '../MainOverlayTextBox';
+import { CheckBox } from '../search/CheckBox';
 
 library.add(faEdit);
 library.add(faSmile, faTextHeight);
@@ -469,7 +470,8 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
                 dispatchTransaction: this.dispatchTransaction,
                 nodeViews: {
                     image(node, view, getPos) { return new ImageResizeView(node, view, getPos); },
-                    star(node, view, getPos) { return new SummarizedView(node, view, getPos); }
+                    star(node, view, getPos) { return new SummarizedView(node, view, getPos); },
+                    checkbox(node, view, getPos) { return new CheckboxView(node, view, getPos) as NodeView<any>; }
                 },
                 clipboardTextSerializer: this.clipboardTextSerializer,
                 handlePaste: this.handlePaste,
-- 
cgit v1.2.3-70-g09d2


From 7aa0d076800c61b7545e2aa12f714eb7ea046eae Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Fri, 9 Aug 2019 10:31:40 -0400
Subject: changed applied templates to have a prototype.

---
 src/client/util/TooltipTextMenu.tsx         |  6 ------
 src/client/views/MainOverlayTextBox.tsx     |  2 +-
 src/client/views/nodes/FormattedTextBox.tsx | 16 ++--------------
 src/client/views/nodes/ImageBox.tsx         |  2 +-
 src/new_fields/Doc.ts                       |  9 +++++++--
 5 files changed, 11 insertions(+), 24 deletions(-)

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

diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx
index d33a52d7f..8dc5cdb2a 100644
--- a/src/client/util/TooltipTextMenu.tsx
+++ b/src/client/util/TooltipTextMenu.tsx
@@ -190,12 +190,6 @@ export class TooltipTextMenu {
         this.updateListItemDropdown(":", this.listTypeBtnDom);
 
         this.update(view, undefined);
-
-        //view.dom.parentNode!.parentNode!.insertBefore(this.tooltip, view.dom.parentNode);
-
-        // add tooltip to outerdiv to circumvent scaling problem
-        const outer_div = this.editorProps.outer_div;
-        outer_div && outer_div(this.wrapper);
     }
 
     //label of dropdown will change to given label
diff --git a/src/client/views/MainOverlayTextBox.tsx b/src/client/views/MainOverlayTextBox.tsx
index 72eb956e3..fccbeb16c 100644
--- a/src/client/views/MainOverlayTextBox.tsx
+++ b/src/client/views/MainOverlayTextBox.tsx
@@ -144,7 +144,7 @@ export class MainOverlayTextBox extends React.Component<MainOverlayTextBoxProps>
                                 DataDoc={FormattedTextBox.InputBoxOverlay.props.DataDoc}
                                 isSelected={returnTrue} select={emptyFunction} renderDepth={0} selectOnLoad={true}
                                 ContainingCollectionView={undefined} whenActiveChanged={emptyFunction} active={returnTrue} ContentScaling={returnOne}
-                                ScreenToLocalTransform={this._textXf} PanelWidth={returnZero} PanelHeight={returnZero} focus={emptyFunction} addDocTab={this.addDocTab} outer_div={(tooltip: HTMLElement) => { this._tooltip = tooltip; this.updateTooltip(); }} />
+                                ScreenToLocalTransform={this._textXf} PanelWidth={returnZero} PanelHeight={returnZero} focus={emptyFunction} addDocTab={this.addDocTab} />
                         </div>
                     </div>
                 </div>
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 44b5d2c21..10f50c5a4 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -30,11 +30,9 @@ import { ContextMenu } from "../../views/ContextMenu";
 import { ContextMenuProps } from '../ContextMenuItem';
 import { DocComponent } from "../DocComponent";
 import { InkingControl } from "../InkingControl";
-import { Templates } from '../Templates';
 import { FieldView, FieldViewProps } from "./FieldView";
 import "./FormattedTextBox.scss";
 import React = require("react");
-import { For } from 'babel-types';
 import { DateField } from '../../../new_fields/DateField';
 import { Utils } from '../../../Utils';
 import { MainOverlayTextBox } from '../MainOverlayTextBox';
@@ -50,7 +48,6 @@ export interface FormattedTextBoxProps {
     hideOnLeave?: boolean;
     height?: string;
     color?: string;
-    outer_div?: (domminus: HTMLElement) => void;
     firstinstance?: boolean;
 }
 
@@ -68,7 +65,6 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
     }
     public static Instance: FormattedTextBox;
     private _ref: React.RefObject<HTMLDivElement>;
-    private _outerdiv?: (dominus: HTMLElement) => void;
     private _proseRef?: HTMLDivElement;
     private _editorView: Opt<EditorView>;
     private static _toolTipTextMenu: TooltipTextMenu | undefined = undefined;
@@ -124,13 +120,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
 
     constructor(props: FieldViewProps) {
         super(props);
-        //if (this.props.firstinstance) {
         FormattedTextBox.Instance = this;
-        //}
-        if (this.props.outer_div) {
-            this._outerdiv = this.props.outer_div;
-        }
-
         this._ref = React.createRef();
         if (this.props.isOverlay) {
             DragManager.StartDragFunctions.push(() => FormattedTextBox.InputBoxOverlay = undefined);
@@ -141,7 +131,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
 
     @computed get extensionDoc() { return Doc.resolvedFieldDataDoc(this.dataDoc, this.props.fieldKey, "dummy"); }
 
-    @computed get dataDoc() { return this.props.DataDoc && (BoolCast(this.props.Document.isTemplate) || BoolCast(this.props.DataDoc.isTemplate) || this.props.DataDoc.layout === this.props.Document) ? this.props.DataDoc : Doc.GetProto(this.props.Document); }
+    @computed get dataDoc() { return this.props.DataDoc && (BoolCast(this.props.Document.isTemplate) || BoolCast(this.props.DataDoc.isTemplate) || this.props.DataDoc.layout === this.props.Document) ? Doc.GetDataDoc(this.props.DataDoc) : Doc.GetProto(this.props.Document); }
 
 
     paste = (e: ClipboardEvent) => {
@@ -206,9 +196,6 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
                     tokens.forEach((word) => {
                         if (terms.includes(word) && this._editorView) {
                             this._editorView.dispatch(this._editorView.state.tr.addMark(start, start + word.length, mark).removeStoredMark(mark));
-                            // else {
-                            //     this._editorView.state.tr.addMark(start, start + word.length, mark).removeStoredMark(mark);
-                            // }
                         }
                         start += word.length + 1;
                     });
@@ -484,6 +471,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
         this._reactionDisposer && this._reactionDisposer();
         this._proxyReactionDisposer && this._proxyReactionDisposer();
         this._textReactionDisposer && this._textReactionDisposer();
+        this._searchReactionDisposer && this._searchReactionDisposer();
     }
 
     onPointerDown = (e: React.PointerEvent): void => {
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index ca0f637eb..1ebeb2d66 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -65,7 +65,7 @@ export class ImageBox extends DocComponent<FieldViewProps, ImageDocument>(ImageD
     private dropDisposer?: DragManager.DragDropDisposer;
 
 
-    @computed get dataDoc() { return this.props.DataDoc && (BoolCast(this.props.Document.isTemplate) || BoolCast(this.props.DataDoc.isTemplate) || this.props.DataDoc.layout === this.props.Document) ? this.props.DataDoc : this.props.Document; }
+    @computed get dataDoc() { return this.props.DataDoc && (BoolCast(this.props.Document.isTemplate) || BoolCast(this.props.DataDoc.isTemplate) || this.props.DataDoc.layout === this.props.Document) ? Doc.GetDataDoc(this.props.DataDoc) : Doc.GetProto(this.props.Document); }
 
 
     protected createDropTarget = (ele: HTMLDivElement) => {
diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts
index ba01cfd9c..1df36d719 100644
--- a/src/new_fields/Doc.ts
+++ b/src/new_fields/Doc.ts
@@ -297,6 +297,10 @@ export namespace Doc {
     export function GetProto(doc: Doc) {
         return Doc.GetT(doc, "isPrototype", "boolean", true) ? doc : (doc.proto || doc);
     }
+    export function GetDataDoc(doc: Doc): Doc {
+        let proto = Doc.GetProto(doc);
+        return proto === doc ? proto : Doc.GetDataDoc(proto);
+    }
 
     export function allKeys(doc: Doc): string[] {
         const results: Set<string> = new Set;
@@ -371,7 +375,7 @@ export namespace Doc {
         docExtensionForField.extendsDoc = doc; // this is used by search to map field matches on the extension doc back to the document it extends.
         docExtensionForField.type = DocumentType.EXTENSION;
         let proto: Doc | undefined = doc;
-        while (proto && !Doc.IsPrototype(proto)) {
+        while (proto && !Doc.IsPrototype(proto) && proto.proto) {
             proto = proto.proto;
         }
         (proto ? proto : doc)[fieldKey + "_ext"] = new PrefetchProxy(docExtensionForField);
@@ -490,7 +494,8 @@ export namespace Doc {
     let _applyCount: number = 0;
     export function ApplyTemplate(templateDoc: Doc) {
         if (!templateDoc) return undefined;
-        let otherdoc = new Doc();
+        let datadoc = new Doc();
+        let otherdoc = Doc.MakeDelegate(datadoc);
         otherdoc.width = templateDoc[WidthSym]();
         otherdoc.height = templateDoc[HeightSym]();
         otherdoc.title = templateDoc.title + "(..." + _applyCount++ + ")";
-- 
cgit v1.2.3-70-g09d2


From 915b9332ad72f56b68df148b09eecba527dc9f06 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Fri, 9 Aug 2019 12:10:36 -0400
Subject: changed how templates get dataDocs.  changed button boxes to be div's

---
 src/client/views/MainView.tsx                      |  2 +-
 .../views/collections/ParentDocumentSelector.tsx   |  8 ++---
 src/client/views/nodes/ButtonBox.scss              |  4 +++
 src/client/views/nodes/ButtonBox.tsx               | 42 ++--------------------
 src/client/views/nodes/DocumentView.tsx            | 36 ++++++++++++++++++-
 src/client/views/nodes/FormattedTextBox.tsx        |  4 +--
 src/client/views/nodes/ImageBox.tsx                |  2 +-
 src/new_fields/Doc.ts                              |  2 +-
 8 files changed, 51 insertions(+), 49 deletions(-)

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

diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index a4db753ab..0d8ade247 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -459,7 +459,7 @@ export class MainView extends React.Component {
             // [React.createRef<HTMLDivElement>(), "clone", "Add Docking Frame", addDockingNode],
             [React.createRef<HTMLDivElement>(), "cloud-upload-alt", "Import Directory", addImportCollectionNode],
             [React.createRef<HTMLDivElement>(), "play", "Add Youtube Searcher", addYoutubeSearcher],
-            [React.createRef<HTMLDivElement>(), "bolt", "Add Document Dragger", addDragboxNode]
+            [React.createRef<HTMLDivElement>(), "file", "Add Document Dragger", addDragboxNode]
         ];
         if (!ClientUtils.RELEASE) btns.unshift([React.createRef<HTMLDivElement>(), "cat", "Add Cat Image", addImageNode]);
 
diff --git a/src/client/views/collections/ParentDocumentSelector.tsx b/src/client/views/collections/ParentDocumentSelector.tsx
index c3e55d825..17111af58 100644
--- a/src/client/views/collections/ParentDocumentSelector.tsx
+++ b/src/client/views/collections/ParentDocumentSelector.tsx
@@ -50,10 +50,10 @@ export class SelectorContextMenu extends React.Component<SelectorProps> {
     render() {
         return (
             <>
-                <p>Contexts:</p>
-                {this._docs.map(doc => <p><a onClick={this.getOnClick(doc)}>{doc.col.title}</a></p>)}
-                {this._otherDocs.length ? <hr></hr> : null}
-                {this._otherDocs.map(doc => <p><a onClick={this.getOnClick(doc)}>{doc.col.title}</a></p>)}
+                <p key="contexts">Contexts:</p>
+                {this._docs.map(doc => <p key={doc.col[Id] + doc.target[Id]}><a onClick={this.getOnClick(doc)}>{doc.col.title}</a></p>)}
+                {this._otherDocs.length ? <hr key="hr" /> : null}
+                {this._otherDocs.map(doc => <p key="p"><a onClick={this.getOnClick(doc)}>{doc.col.title}</a></p>)}
             </>
         );
     }
diff --git a/src/client/views/nodes/ButtonBox.scss b/src/client/views/nodes/ButtonBox.scss
index 92beafa15..5ed435505 100644
--- a/src/client/views/nodes/ButtonBox.scss
+++ b/src/client/views/nodes/ButtonBox.scss
@@ -3,10 +3,14 @@
     height: 100%;
     pointer-events: all;
     border-radius: inherit;
+    display:table;
 }
 
 .buttonBox-mainButton {
     width: 100%;
     height: 100%;
     border-radius: inherit;
+    display:table-cell;
+    vertical-align: middle;
+    text-align: center;
 }
\ No newline at end of file
diff --git a/src/client/views/nodes/ButtonBox.tsx b/src/client/views/nodes/ButtonBox.tsx
index 640795789..8b6f11aac 100644
--- a/src/client/views/nodes/ButtonBox.tsx
+++ b/src/client/views/nodes/ButtonBox.tsx
@@ -15,6 +15,7 @@ import { Doc } from '../../../new_fields/Doc';
 import './ButtonBox.scss';
 import { observer } from 'mobx-react';
 import { DocumentIconContainer } from './DocumentIcon';
+import { StrCast } from '../../../new_fields/Types';
 
 library.add(faEdit as any);
 
@@ -30,47 +31,10 @@ const ButtonDocument = makeInterface(ButtonSchema);
 export class ButtonBox extends DocComponent<FieldViewProps, ButtonDocument>(ButtonDocument) {
     public static LayoutString() { return FieldView.LayoutString(ButtonBox); }
 
-    onClick = (e: React.MouseEvent) => {
-        const onClick = this.Document.onClick;
-        if (!onClick) {
-            return;
-        }
-        e.stopPropagation();
-        e.preventDefault();
-        onClick.script.run({ this: this.props.Document });
-    }
-
-    onContextMenu = () => {
-        ContextMenu.Instance.addItem({
-            description: "Edit OnClick script", icon: "edit", event: () => {
-                let overlayDisposer: () => void = emptyFunction;
-                const script = this.Document.onClick;
-                let originalText: string | undefined = undefined;
-                if (script) originalText = script.script.originalScript;
-                // tslint:disable-next-line: no-unnecessary-callback-wrapper
-                let scriptingBox = <ScriptBox initialText={originalText} onCancel={() => overlayDisposer()} onSave={(text, onError) => {
-                    const script = CompileScript(text, {
-                        params: { this: Doc.name },
-                        typecheck: false,
-                        editable: true,
-                        transformer: DocumentIconContainer.getTransformer()
-                    });
-                    if (!script.compiled) {
-                        onError(script.errors.map(error => error.messageText).join("\n"));
-                        return;
-                    }
-                    this.Document.onClick = new ScriptField(script);
-                    overlayDisposer();
-                }} showDocumentIcons />;
-                overlayDisposer = OverlayView.Instance.addWindow(scriptingBox, { x: 400, y: 200, width: 500, height: 400, title: `${this.Document.title || ""} OnClick` });
-            }
-        });
-    }
-
     render() {
         return (
-            <div className="buttonBox-outerDiv" onContextMenu={this.onContextMenu}>
-                <button className="buttonBox-mainButton" onClick={this.onClick}>{this.Document.text || this.Document.title || "Button"}</button>
+            <div className="buttonBox-outerDiv" >
+                <div className="buttonBox-mainButton" style={{ background: StrCast(this.props.Document.backgroundColor), color: StrCast(this.props.Document.color, "black") }} >{this.Document.text || this.Document.title}</div>
             </div>
         );
     }
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index c8eab85c2..cf16db203 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -40,6 +40,10 @@ import React = require("react");
 import { DictationManager } from '../../util/DictationManager';
 import { MainView } from '../MainView';
 import requestPromise = require('request-promise');
+import { ScriptBox } from '../ScriptBox';
+import { CompileScript } from '../../util/Scripting';
+import { DocumentIconContainer } from './DocumentIcon';
+import { ScriptField } from '../../../new_fields/ScriptField';
 const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this?
 
 library.add(fa.faTrash);
@@ -109,7 +113,8 @@ const schema = createSchema({
     nativeHeight: "number",
     backgroundColor: "string",
     opacity: "number",
-    hidden: "boolean"
+    hidden: "boolean",
+    onClick: ScriptField,
 });
 
 export const positionSchema = createSchema({
@@ -292,6 +297,11 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     onClick = async (e: React.MouseEvent) => {
         if (e.nativeEvent.cancelBubble) return; // needed because EditableView may stopPropagation which won't apparently stop this event from firing.
         e.stopPropagation();
+        if (this.Document.onClick) {
+            this.Document.onClick.script.run({ this: this.props.Document });
+            e.preventDefault();
+            return;
+        }
         let altKey = e.altKey;
         let ctrlKey = e.ctrlKey;
         if (this._doubleTap && this.props.renderDepth) {
@@ -567,6 +577,30 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         cm.addItem({ description: "Pin to Presentation", event: () => PresentationView.Instance.PinDoc(this.props.Document), icon: "map-pin" });
         cm.addItem({ description: BoolCast(this.props.Document.lockedPosition) ? "Unlock Position" : "Lock Position", event: this.toggleLockPosition, icon: BoolCast(this.props.Document.lockedPosition) ? "unlock" : "lock" });
         cm.addItem({ description: "Transcribe Speech", event: this.listen, icon: "microphone" });
+        cm.addItem({
+            description: "Edit OnClick script", icon: "edit", event: () => {
+                let overlayDisposer: () => void = emptyFunction;
+                const script = this.Document.onClick;
+                let originalText: string | undefined = undefined;
+                if (script) originalText = script.script.originalScript;
+                // tslint:disable-next-line: no-unnecessary-callback-wrapper
+                let scriptingBox = <ScriptBox initialText={originalText} onCancel={() => overlayDisposer()} onSave={(text, onError) => {
+                    const script = CompileScript(text, {
+                        params: { this: Doc.name },
+                        typecheck: false,
+                        editable: true,
+                        transformer: DocumentIconContainer.getTransformer()
+                    });
+                    if (!script.compiled) {
+                        onError(script.errors.map(error => error.messageText).join("\n"));
+                        return;
+                    }
+                    this.Document.onClick = new ScriptField(script);
+                    overlayDisposer();
+                }} showDocumentIcons />;
+                overlayDisposer = OverlayView.Instance.addWindow(scriptingBox, { x: 400, y: 200, width: 500, height: 400, title: `${this.Document.title || ""} OnClick` });
+            }
+        });
         let makes: ContextMenuProps[] = [];
         makes.push({ description: this.props.Document.isBackground ? "Remove Background" : "Make Background", event: this.makeBackground, icon: BoolCast(this.props.Document.lockedPosition) ? "unlock" : "lock" });
         makes.push({ description: this.props.Document.isButton ? "Remove Button" : "Make Button", event: this.makeBtnClicked, icon: "concierge-bell" });
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 10f50c5a4..cf4f7f668 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -131,7 +131,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
 
     @computed get extensionDoc() { return Doc.resolvedFieldDataDoc(this.dataDoc, this.props.fieldKey, "dummy"); }
 
-    @computed get dataDoc() { return this.props.DataDoc && (BoolCast(this.props.Document.isTemplate) || BoolCast(this.props.DataDoc.isTemplate) || this.props.DataDoc.layout === this.props.Document) ? Doc.GetDataDoc(this.props.DataDoc) : Doc.GetProto(this.props.Document); }
+    @computed get dataDoc() { return this.props.DataDoc && (BoolCast(this.props.Document.isTemplate) || BoolCast(this.props.DataDoc.isTemplate) || this.props.DataDoc.layout === this.props.Document) ? this.props.DataDoc : Doc.GetProto(this.props.Document); }
 
 
     paste = (e: ClipboardEvent) => {
@@ -624,7 +624,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
             let self = this;
             let xf = this._ref.current!.getBoundingClientRect();
             let scrBounds = this.props.ScreenToLocalTransform().transformBounds(0, 0, xf.width, xf.height);
-            let nh = NumCast(this.dataDoc.nativeHeight, 0);
+            let nh = this.props.Document.isTemplate ? 0 : NumCast(this.dataDoc.nativeHeight, 0);
             let dh = NumCast(this.props.Document.height, 0);
             let sh = scrBounds.height;
             const ChromeHeight = MainOverlayTextBox.Instance.ChromeHeight;
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 1ebeb2d66..78a6ec66f 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -65,7 +65,7 @@ export class ImageBox extends DocComponent<FieldViewProps, ImageDocument>(ImageD
     private dropDisposer?: DragManager.DragDropDisposer;
 
 
-    @computed get dataDoc() { return this.props.DataDoc && (BoolCast(this.props.Document.isTemplate) || BoolCast(this.props.DataDoc.isTemplate) || this.props.DataDoc.layout === this.props.Document) ? Doc.GetDataDoc(this.props.DataDoc) : Doc.GetProto(this.props.Document); }
+    @computed get dataDoc() { return this.props.DataDoc && (BoolCast(this.props.Document.isTemplate) || BoolCast(this.props.DataDoc.isTemplate) || this.props.DataDoc.layout === this.props.Document) ? this.props.DataDoc : Doc.GetProto(this.props.Document); }
 
 
     protected createDropTarget = (ele: HTMLDivElement) => {
diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts
index 1df36d719..fc4411d93 100644
--- a/src/new_fields/Doc.ts
+++ b/src/new_fields/Doc.ts
@@ -446,7 +446,7 @@ export namespace Doc {
 
     export function GetLayoutDataDocPair(doc: Doc, dataDoc: Doc | undefined, fieldKey: string, childDocLayout: Doc) {
         let layoutDoc = childDocLayout;
-        let resolvedDataDoc = !doc.isTemplate && dataDoc !== doc ? dataDoc : undefined;
+        let resolvedDataDoc = !doc.isTemplate && dataDoc !== doc && dataDoc ? Doc.GetDataDoc(dataDoc) : undefined;
         if (resolvedDataDoc && Doc.WillExpandTemplateLayout(childDocLayout, resolvedDataDoc)) {
             Doc.UpdateDocumentExtensionForField(resolvedDataDoc, fieldKey);
             let fieldExtensionDoc = Doc.resolvedFieldDataDoc(resolvedDataDoc, StrCast(childDocLayout.templateField, StrCast(childDocLayout.title)), "dummy");
-- 
cgit v1.2.3-70-g09d2


From 8c4b8ae12fb418d38e5aab6c12514913f1565bb0 Mon Sep 17 00:00:00 2001
From: monikahedman <monika_hedman@brown.edu>
Date: Fri, 9 Aug 2019 17:02:02 -0400
Subject: send halp

---
 src/client/util/RichTextSchema.tsx                 | 52 +++++++++++-----------
 src/client/util/TooltipTextMenu.tsx                |  9 ++--
 .../views/collections/CollectionViewChromes.tsx    |  2 +
 src/client/views/nodes/FormattedTextBox.tsx        |  1 +
 4 files changed, 33 insertions(+), 31 deletions(-)

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

diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx
index 8e80de1a8..733c50d20 100644
--- a/src/client/util/RichTextSchema.tsx
+++ b/src/client/util/RichTextSchema.tsx
@@ -6,6 +6,7 @@ import { orderedList, bulletList, listItem, } from 'prosemirror-schema-list';
 import { EditorState, Transaction, NodeSelection, TextSelection, Selection, } from "prosemirror-state";
 import { EditorView, } from "prosemirror-view";
 import { View } from '@react-pdf/renderer';
+import { TooltipTextMenu } from './TooltipTextMenu';
 
 const pDOM: DOMOutputSpecArray = ["p", 0], blockquoteDOM: DOMOutputSpecArray = ["blockquote", 0], hrDOM: DOMOutputSpecArray = ["hr"],
     preDOM: DOMOutputSpecArray = ["pre", ["code", 0]], brDOM: DOMOutputSpecArray = ["br"], ulDOM: DOMOutputSpecArray = ["ul", 0];
@@ -111,30 +112,16 @@ export const nodes: { [index: string]: NodeSpec } = {
         // }]
     },
 
-    // TODO
     checkbox: {
         inline: true,
         attrs: {
-            visibility: { default: false },
-            // text: { default: undefined },
-            // textslice: { default: undefined },
-            // textlen: { default: 0 }
-
+            visibility: { default: false }
         },
         group: "inline",
         toDOM(node) {
             const attrs = { style: `width: 40px` };
             return ["span", { ...node.attrs, ...attrs }];
         },
-        // parseDOM: [{
-        //     tag: "star", getAttrs(dom: any) {
-        //         return {
-        //             visibility: dom.getAttribute("visibility"),
-        //             oldtext: dom.getAttribute("oldtext"),
-        //             oldtextlen: dom.getAttribute("oldtextlen"),
-        //         }
-        //     }
-        // }]
     },
 
     // :: NodeSpec An inline image (`<img>`) node. Supports `src`,
@@ -193,12 +180,6 @@ export const nodes: { [index: string]: NodeSpec } = {
         }
     },
 
-    checkbox_list2: {
-        inline: false,
-        // content: 'list_item+',
-        group: 'block'
-    },
-
     // :: NodeSpec A hard line break, represented in the DOM as `<br>`.
     hard_break: {
         inline: true,
@@ -221,15 +202,20 @@ export const nodes: { [index: string]: NodeSpec } = {
         // parseDOM: [{ tag: "ul" }, { style: 'list-style-type=disc' }],
         // toDOM() { return ulDOM }
     },
+
     checkbox_list: {
-        ...bulletList,
-        content: 'list_item+',
+        content: 'checklist_item+',
+        marks: '_',
         group: 'block',
-        // style: 'list-style-type:none'
-        itemContent: "+",
-        // parseDOM: [{ tag: "ul" }, { style: 'list-style-type=square' }],
-        // toDOM() { return ulDOM; }
+        // inline: true,
+        parseDOM: [
+            { tag: "ul" }
+        ],
+        toDOM() {
+            return ["ul", { style: 'list-style: none' }, 0];
+        },
     },
+
     //bullet_list: {
     //  content: 'list_item+',
     // group: 'block',
@@ -241,6 +227,18 @@ export const nodes: { [index: string]: NodeSpec } = {
     list_item: {
         ...listItem,
         content: 'paragraph block*'
+    },
+
+    checklist_item: {
+        content: 'paragraph block*',
+        parseDOM: [{ tag: "li" }],
+        // toDOM() {
+        //     return ["li", { style: 'content: checkbox' }, 0];
+        // },
+        toDOM() {
+            return ["li", 0];
+        },
+        defining: true
     }
 };
 
diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx
index b1243cb1d..8112ed868 100644
--- a/src/client/util/TooltipTextMenu.tsx
+++ b/src/client/util/TooltipTextMenu.tsx
@@ -441,13 +441,10 @@ export class TooltipTextMenu {
         return true;
     }
 
-    // this needs to change so it makes it into a bulleted list
     public static insertCheckbox(state: EditorState<any>, dispatch: any) {
         let newNode = schema.nodes.checkbox.create({ visibility: false });
         if (dispatch) {
-            //console.log(newNode.attrs.text.toString());
             dispatch(state.tr.replaceSelectionWith(newNode));
-            wrapInList(newNode.type)(state, dispatch);
         }
         return true;
     }
@@ -461,7 +458,6 @@ export class TooltipTextMenu {
         let toAdd: MenuItem[] = [];
         this.listTypeToIcon.forEach((icon, type) => {
             toAdd.push(this.dropdownNodeBtn(icon, "color: black; width: 40px;", type, this.view, this.listTypes, this.changeToNodeType));
-            console.log(type.name)
         });
         //option to remove the list formatting
         toAdd.push(this.dropdownNodeBtn("X", "color: black; width: 40px;", undefined, this.view, this.listTypes, this.changeToNodeType));
@@ -529,6 +525,11 @@ export class TooltipTextMenu {
         liftListItem(schema.nodes.list_item)(view.state, view.dispatch);
         if (nodeType) { //add new
             wrapInList(nodeType)(view.state, view.dispatch);
+            // console.log(nodeType === schema.nodes.checkbox_list)
+            // if (nodeType === schema.nodes.checkbox_list) {
+            //     TooltipTextMenu.insertCheckbox(view.state, view.dispatch)
+            // }
+
         }
     }
 
diff --git a/src/client/views/collections/CollectionViewChromes.tsx b/src/client/views/collections/CollectionViewChromes.tsx
index 52c47e7e8..5b673c8ec 100644
--- a/src/client/views/collections/CollectionViewChromes.tsx
+++ b/src/client/views/collections/CollectionViewChromes.tsx
@@ -33,6 +33,8 @@ let stopPropagation = (e: React.SyntheticEvent) => e.stopPropagation();
 
 @observer
 export class CollectionViewBaseChrome extends React.Component<CollectionViewChromeProps> {
+    //.*?doc\.(\w+).*?\("(\w+)
+
     @observable private _viewSpecsOpen: boolean = false;
     @observable private _dateWithinValue: string = "";
     @observable private _dateValue: Date | string = "";
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 303b1ac88..d1771eb0f 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -177,6 +177,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
             this._editorView.updateState(state);
             if (state.selection.empty && FormattedTextBox._toolTipTextMenu) {
                 const marks = tx.storedMarks;
+                console.log(marks)
                 if (marks) { FormattedTextBox._toolTipTextMenu.mark_key_pressed(marks); }
             }
             this._applyingChange = true;
-- 
cgit v1.2.3-70-g09d2


From afec8d91ec6de13de33e2a31c987727b4cc7101d Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Tue, 13 Aug 2019 15:42:05 -0400
Subject: changes to fix stacking layouts used with templates. rearrangement of
 menu options.

---
 src/client/util/TooltipTextMenu.tsx                |   2 +-
 src/client/views/DocumentDecorations.tsx           |   4 +-
 src/client/views/InkingCanvas.tsx                  |  20 ++--
 src/client/views/ScriptBox.tsx                     |  30 +++++-
 .../views/collections/CollectionDockingView.tsx    |   4 +-
 .../views/collections/CollectionStackingView.tsx   |  57 +++++++----
 .../CollectionStackingViewFieldColumn.tsx          |   2 +-
 src/client/views/collections/CollectionView.tsx    |  19 ++--
 .../views/collections/CollectionViewChromes.tsx    |  19 ++--
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  64 ++-----------
 src/client/views/nodes/DocumentContentsView.tsx    |   3 +-
 src/client/views/nodes/DocumentView.tsx            | 105 ++++++++++++---------
 src/client/views/nodes/FormattedTextBox.tsx        |  15 +--
 src/new_fields/Doc.ts                              |   7 ++
 src/new_fields/Types.ts                            |   4 +
 15 files changed, 193 insertions(+), 162 deletions(-)

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

diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx
index 8dc5cdb2a..48f02d38a 100644
--- a/src/client/util/TooltipTextMenu.tsx
+++ b/src/client/util/TooltipTextMenu.tsx
@@ -963,7 +963,7 @@ export class TooltipTextMenu {
                 });
             }
         }
-        if (!ref_node.isLeaf) {
+        if (!ref_node.isLeaf && ref_node.childCount > 0) {
             ref_node = ref_node.child(0);
         }
         return ref_node;
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 6616d5d58..d537e2dac 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -537,12 +537,12 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
                 doc.x = (doc.x || 0) + dX * (actualdW - width);
                 doc.y = (doc.y || 0) + dY * (actualdH - height);
                 let proto = doc.isTemplate ? doc : Doc.GetProto(element.props.Document); // bcz: 'doc' didn't work here...
-                let fixedAspect = e.ctrlKey || (!BoolCast(proto.ignoreAspect) && nwidth && nheight);
+                let fixedAspect = e.ctrlKey || (!BoolCast(doc.ignoreAspect) && nwidth && nheight);
                 if (fixedAspect && (!nwidth || !nheight)) {
                     proto.nativeWidth = nwidth = doc.width || 0;
                     proto.nativeHeight = nheight = doc.height || 0;
                 }
-                if (nwidth > 0 && nheight > 0 && !BoolCast(proto.ignoreAspect)) {
+                if (nwidth > 0 && nheight > 0 && !BoolCast(doc.ignoreAspect)) {
                     if (Math.abs(dW) > Math.abs(dH)) {
                         if (!fixedAspect) {
                             Doc.SetInPlace(element.props.Document, "nativeWidth", actualdW / (doc.width || 1) * (doc.nativeWidth || 0), true);
diff --git a/src/client/views/InkingCanvas.tsx b/src/client/views/InkingCanvas.tsx
index 1c221e3df..b08133d80 100644
--- a/src/client/views/InkingCanvas.tsx
+++ b/src/client/views/InkingCanvas.tsx
@@ -165,14 +165,18 @@ export class InkingCanvas extends React.Component<InkCanvasProps> {
             }
             return paths;
         }, [] as JSX.Element[]);
-        return [<svg className={`inkingCanvas-paths-ink`} key="Pens"
-            style={{ left: `${this.inkMidX - this.maxCanvasDim}px`, top: `${this.inkMidY - this.maxCanvasDim}px` }} >
-            {paths.filter(path => path.props.tool !== InkTool.Highlighter)}
-        </svg>,
-        <svg className={`inkingCanvas-paths-markers`} key="Markers"
-            style={{ left: `${this.inkMidX - this.maxCanvasDim}px`, top: `${this.inkMidY - this.maxCanvasDim}px` }}>
-            {paths.filter(path => path.props.tool === InkTool.Highlighter)}
-        </svg>];
+        let markerPaths = paths.filter(path => path.props.tool === InkTool.Highlighter);
+        let penPaths = paths.filter(path => path.props.tool !== InkTool.Highlighter);
+        return [!penPaths.length ? (null) :
+            <svg className={`inkingCanvas-paths-ink`} key="Pens"
+                style={{ left: `${this.inkMidX - this.maxCanvasDim}px`, top: `${this.inkMidY - this.maxCanvasDim}px` }} >
+                {}
+            </svg>,
+        !markerPaths.length ? (null) :
+            <svg className={`inkingCanvas-paths-markers`} key="Markers"
+                style={{ left: `${this.inkMidX - this.maxCanvasDim}px`, top: `${this.inkMidY - this.maxCanvasDim}px` }}>
+                {}
+            </svg>];
     }
 
     render() {
diff --git a/src/client/views/ScriptBox.tsx b/src/client/views/ScriptBox.tsx
index d073945e5..2b862a81e 100644
--- a/src/client/views/ScriptBox.tsx
+++ b/src/client/views/ScriptBox.tsx
@@ -5,7 +5,11 @@ import { observable, action } from "mobx";
 import "./ScriptBox.scss";
 import { OverlayView } from "./OverlayView";
 import { DocumentIconContainer } from "./nodes/DocumentIcon";
-import { Opt } from "../../new_fields/Doc";
+import { Opt, Doc } from "../../new_fields/Doc";
+import { emptyFunction } from "../../Utils";
+import { ScriptCast } from "../../new_fields/Types";
+import { CompileScript } from "../util/Scripting";
+import { ScriptField } from "../../new_fields/ScriptField";
 
 export interface ScriptBoxProps {
     onSave: (text: string, onError: (error: string) => void) => void;
@@ -62,4 +66,26 @@ export class ScriptBox extends React.Component<ScriptBoxProps> {
             </div>
         );
     }
-}
\ No newline at end of file
+    public static EditClickScript(doc: Doc, fieldKey: string) {
+        let overlayDisposer: () => void = emptyFunction;
+        const script = ScriptCast(doc[fieldKey]);
+        let originalText: string | undefined = undefined;
+        if (script) originalText = script.script.originalScript;
+        // tslint:disable-next-line: no-unnecessary-callback-wrapper
+        let scriptingBox = <ScriptBox initialText={originalText} onCancel={() => overlayDisposer()} onSave={(text, onError) => {
+            const script = CompileScript(text, {
+                params: { this: Doc.name },
+                typecheck: false,
+                editable: true,
+                transformer: DocumentIconContainer.getTransformer()
+            });
+            if (!script.compiled) {
+                onError(script.errors.map(error => error.messageText).join("\n"));
+                return;
+            }
+            doc[fieldKey] = new ScriptField(script);
+            overlayDisposer();
+        }} showDocumentIcons />;
+        overlayDisposer = OverlayView.Instance.addWindow(scriptingBox, { x: 400, y: 200, width: 500, height: 400, title: `${doc.title || ""} OnClick` });
+    }
+}
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index c0c82a44e..13bb34037 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -555,8 +555,8 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
     panelWidth = () => this._document!.ignoreAspect ? this._panelWidth : Math.min(this._panelWidth, Math.max(NumCast(this._document!.width), this.nativeWidth()));
     panelHeight = () => this._document!.ignoreAspect ? this._panelHeight : Math.min(this._panelHeight, Math.max(NumCast(this._document!.height), NumCast(this._document!.nativeHeight, this._panelHeight)));
 
-    nativeWidth = () => !BoolCast(this._document!.ignoreAspect) ? NumCast(this._document!.nativeWidth, this._panelWidth) : 0;
-    nativeHeight = () => !BoolCast(this._document!.ignoreAspect) ? NumCast(this._document!.nativeHeight, this._panelHeight) : 0;
+    nativeWidth = () => !this._document!.ignoreAspect ? NumCast(this._document!.nativeWidth) || this._panelWidth : 0;
+    nativeHeight = () => !this._document!.ignoreAspect ? NumCast(this._document!.nativeHeight) || this._panelHeight : 0;
 
     contentScaling = () => {
         const nativeH = this.nativeHeight();
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 9d2671356..ba3d8e6a7 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -9,7 +9,7 @@ import { Id } from "../../../new_fields/FieldSymbols";
 import { List } from "../../../new_fields/List";
 import { listSpec } from "../../../new_fields/Schema";
 import { SchemaHeaderField } from "../../../new_fields/SchemaHeaderField";
-import { BoolCast, Cast, NumCast, StrCast } from "../../../new_fields/Types";
+import { BoolCast, Cast, NumCast, StrCast, ScriptCast } from "../../../new_fields/Types";
 import { emptyFunction } from "../../../Utils";
 import { DocumentType } from "../../documents/Documents";
 import { DragManager } from "../../util/DragManager";
@@ -20,6 +20,9 @@ import { CollectionSchemaPreview } from "./CollectionSchemaView";
 import "./CollectionStackingView.scss";
 import { CollectionStackingViewFieldColumn } from "./CollectionStackingViewFieldColumn";
 import { CollectionSubView } from "./CollectionSubView";
+import { ContextMenu } from "../ContextMenu";
+import { ContextMenuProps } from "../ContextMenuItem";
+import { ScriptBox } from "../ScriptBox";
 
 @observer
 export class CollectionStackingView extends CollectionSubView(doc => doc) {
@@ -76,17 +79,24 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
 
     componentDidMount() {
         // is there any reason this needs to exist? -syip
-        this._heightDisposer = reaction(() => [this.props.Document.autoHeight, this.yMargin, this.props.Document[WidthSym](), this.gridGap, this.columnWidth, this.childDocs.map(d => [d.height, d.width, d.zoomBasis, d.nativeHeight, d.nativeWidth, d.isMinimized])],
-            () => {
-                if (this.singleColumn && BoolCast(this.props.Document.autoHeight)) {
-                    let hgt = this.Sections.size * 50 + this.filteredChildren.reduce((height, d, i) => {
-                        let pair = Doc.GetLayoutDataDocPair(this.props.Document, this.props.DataDoc, this.props.fieldKey, d);
-                        return height + this.getDocHeight(pair.layout) + (i === this.filteredChildren.length - 1 ? this.yMargin : this.gridGap);
-                    }, this.yMargin);
-                    (this.props.DataDoc && this.props.DataDoc.layout === this.layoutDoc ? this.props.DataDoc : this.layoutDoc)
-                        .height = hgt * (this.props as any).ContentScaling();
+        this._heightDisposer = reaction(() => {
+            if (this.singleColumn && BoolCast(this.props.Document.autoHeight)) {
+                let hgt = this.Sections.size * 50 + this.filteredChildren.reduce((height, d, i) => {
+                    let pair = Doc.GetLayoutDataDocPair(this.props.Document, this.props.DataDoc, this.props.fieldKey, d);
+                    return height + this.getDocHeight(pair.layout) + (i === this.filteredChildren.length - 1 ? this.yMargin : this.gridGap);
+                }, this.yMargin);
+                return hgt * this.props.ContentScaling();
+            }
+            return -1;
+        },
+            (hgt: number) => {
+                if (hgt !== -1) {
+                    let doc = this.props.DataDoc && this.props.DataDoc.layout === this.layoutDoc ? this.props.DataDoc : this.layoutDoc;
+                    doc.height = hgt;
                 }
-            }, { fireImmediately: true });
+            },
+            { fireImmediately: true }
+        );
 
         // reset section headers when a new filter is inputted
         this._sectionFilterDisposer = reaction(
@@ -109,9 +119,12 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
     }
 
     overlays = (doc: Doc) => {
-        return doc.type === DocumentType.IMG || doc.type === DocumentType.VID ? { title: "title", caption: "caption" } : {};
+        return doc.type === DocumentType.IMG || doc.type === DocumentType.VID ? { title: StrCast(this.props.Document.showTitles), caption: StrCast(this.props.Document.showCaptions) } : {};
     }
 
+    @computed get onChildClickHandler() { return ScriptCast(this.Document.onChildClick); }
+    @computed get onClickHandler() { return this.props.onClick ? this.props.onClick : ScriptCast(this.Document.onChildClick); }
+
     getDisplayDoc(layoutDoc: Doc, dataDoc: Doc | undefined, dxf: () => Transform, width: () => number) {
         let height = () => this.getDocHeight(layoutDoc);
         let finalDxf = () => dxf().scale(this.columnWidth / layoutDoc[WidthSym]());
@@ -121,7 +134,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
             showOverlays={this.overlays}
             renderDepth={this.props.renderDepth}
             fitToBox={this.props.fitToBox}
-            onClick={this.props.onClick}
+            onClick={layoutDoc.isTemplate ? this.onClickHandler : this.onChildClickHandler}
             width={width}
             height={height}
             getTransform={finalDxf}
@@ -141,7 +154,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
         let nh = NumCast(d.nativeHeight);
         if (!d.ignoreAspect && nw && nh) {
             let aspect = nw && nh ? nh / nw : 1;
-            let wid = this.props.Document.fillColumn ? this.columnWidth / columnScale : Math.min(d[WidthSym](), this.columnWidth / columnScale);
+            let wid = this.props.Document.fillColumn ? this.columnWidth / columnScale : Math.min(Math.min(d[WidthSym](), NumCast(d.nativeWidth)), this.columnWidth / columnScale);
             return wid * aspect;
         }
         return d[HeightSym]();
@@ -267,7 +280,19 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
     }
 
     onToggle = (checked: Boolean) => {
-        this.props.CollectionView.props.Document.chromeSatus = checked ? "collapsed" : "view-mode";
+        this.props.CollectionView.props.Document.chromeStatus = checked ? "collapsed" : "view-mode";
+    }
+
+    onContextMenu = (e: React.MouseEvent): void => {
+        // need to test if propagation has stopped because GoldenLayout forces a parallel react hierarchy to be created for its top-level layout
+        if (!e.isPropagationStopped()) {
+            let subItems: ContextMenuProps[] = [];
+            subItems.push({ description: `${this.props.Document.fillColumn ? "Variable Size" : "Autosize"} Column`, event: () => this.props.Document.fillColumn = !this.props.Document.fillColumn, icon: "plus" });
+            subItems.push({ description: `${this.props.Document.showTitles ? "Hide Titles" : "Show Titles"}`, event: () => this.props.Document.showTitles = !this.props.Document.showTitles ? "title" : "", icon: "plus" });
+            subItems.push({ description: `${this.props.Document.showCaptions ? "Hide Captions" : "Show Captions"}`, event: () => this.props.Document.showCaptions = !this.props.Document.showCaptions ? "caption" : "", icon: "plus" });
+            subItems.push({ description: "Edit onChildClick script", icon: "edit", event: () => ScriptBox.EditClickScript(this.props.Document, "onChildClick") });
+            ContextMenu.Instance.addItem({ description: "Stacking Options ...", subitems: subItems, icon: "eye" });
+        }
     }
 
     render() {
@@ -282,7 +307,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
         // let uniqueHeadings = headings.map((i, idx) => headings.indexOf(i) === idx);
         return (
             <div className="collectionStackingView"
-                ref={this.createRef} onDrop={this.onDrop.bind(this)} onWheel={(e: React.WheelEvent) => e.stopPropagation()} >
+                ref={this.createRef} onDrop={this.onDrop.bind(this)} onContextMenu={this.onContextMenu} onWheel={(e: React.WheelEvent) => e.stopPropagation()} >
                 {this.sectionFilter ? Array.from(this.Sections.entries()).sort(this.sortFunc).
                     map((section: [SchemaHeaderField, Doc[]]) => this.section(section[0], section[1])) :
                     this.section(undefined, this.filteredChildren)}
diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
index 817f9f4cb..9824a501b 100644
--- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
+++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
@@ -84,7 +84,7 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
             let headings = this.props.headings();
             let uniqueHeadings = headings.map((i, idx) => headings.indexOf(i) === idx);
             let pair = Doc.GetLayoutDataDocPair(parent.props.Document, parent.props.DataDoc, parent.props.fieldKey, d);
-            let width = () => (d.nativeWidth && !d.ignoreAspect && !parent.props.Document.fillColumn ? Math.min(NumCast(d.nativeWidth), parent.columnWidth / (uniqueHeadings.length + 1)) : parent.columnWidth / (uniqueHeadings.length + 1));/// (uniqueHeadings.length + 1);
+            let width = () => (d.nativeWidth && !d.ignoreAspect && !parent.props.Document.fillColumn ? Math.min(Math.min(d[WidthSym](), NumCast(d.nativeWidth)), parent.columnWidth / (uniqueHeadings.length + 1)) : parent.columnWidth / (uniqueHeadings.length + 1));/// (uniqueHeadings.length + 1);
             let height = () => parent.getDocHeight(pair.layout, uniqueHeadings.length + 1);// / (d.nativeWidth && !BoolCast(d.ignoreAspect) ? uniqueHeadings.length + 1 : 1);
             let dref = React.createRef<HTMLDivElement>();
             // if (uniqueHeadings.length > 0) {
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 8b939259c..aaaa623fb 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -30,7 +30,7 @@ export class CollectionView extends React.Component<FieldViewProps> {
 
     public static LayoutString(fieldStr: string = "data", fieldExt: string = "") { return FieldView.LayoutString(CollectionView, fieldStr, fieldExt); }
 
-    constructor(props:any) {
+    constructor(props: any) {
         super(props);
     }
 
@@ -69,7 +69,7 @@ export class CollectionView extends React.Component<FieldViewProps> {
     @action
     private collapse = (value: boolean) => {
         this._collapsed = value;
-        this.props.Document.chromeStatus = value ? "collapsed" : "visible";
+        this.props.Document.chromeStatus = value ? "collapsed" : "enabled";
     }
 
     private SubView = (type: CollectionViewType, renderProps: CollectionRenderProps) => {
@@ -90,12 +90,7 @@ export class CollectionView extends React.Component<FieldViewProps> {
     onContextMenu = (e: React.MouseEvent): void => {
         if (!this.isAnnotationOverlay && !e.isPropagationStopped() && this.props.Document[Id] !== CurrentUserUtils.MainDocId) { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7
             let subItems: ContextMenuProps[] = [];
-            subItems.push({
-                description: "Freeform", event: () => {
-                    this.props.Document.viewType = CollectionViewType.Freeform;
-                    delete this.props.Document.usePivotLayout;
-                }, icon: "signature"
-            });
+            subItems.push({ description: "Freeform", event: () => { this.props.Document.viewType = CollectionViewType.Freeform; delete this.props.Document.usePivotLayout; }, icon: "signature" });
             if (CollectionBaseView.InSafeMode()) {
                 ContextMenu.Instance.addItem({ description: "Test Freeform", event: () => this.props.Document.viewType = CollectionViewType.Invalid, icon: "project-diagram" });
             }
@@ -111,10 +106,10 @@ export class CollectionView extends React.Component<FieldViewProps> {
                 }
             }
             ContextMenu.Instance.addItem({ description: "View Modes...", subitems: subItems, icon: "eye" });
-            ContextMenu.Instance.addItem({ description: "Apply Template", event: () => this.props.addDocTab && this.props.addDocTab(Doc.ApplyTemplate(this.props.Document)!, undefined, "onRight"), icon: "project-diagram" });
-            ContextMenu.Instance.addItem({
-                description: this.props.Document.chromeStatus !== "disabled" ? "Hide Chrome" : "Show Chrome", event: () => this.props.Document.chromeStatus = (this.props.Document.chromeStatus !== "disabled" ? "disabled" : "enabled"), icon: "project-diagram"
-            });
+            let existing = ContextMenu.Instance.findByDescription("Layout...");
+            let layoutItems: ContextMenuProps[] = existing && "subitems" in existing ? existing.subitems : [];
+            layoutItems.push({ description: "Create Layout Instance", event: () => this.props.addDocTab && this.props.addDocTab(Doc.ApplyTemplate(this.props.Document)!, undefined, "onRight"), icon: "project-diagram" });
+            !existing && ContextMenu.Instance.addItem({ description: "Layout...", subitems: layoutItems, icon: "hand-point-right" });
         }
     }
 
diff --git a/src/client/views/collections/CollectionViewChromes.tsx b/src/client/views/collections/CollectionViewChromes.tsx
index 52c47e7e8..bccc0a5b2 100644
--- a/src/client/views/collections/CollectionViewChromes.tsx
+++ b/src/client/views/collections/CollectionViewChromes.tsx
@@ -37,7 +37,6 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro
     @observable private _dateWithinValue: string = "";
     @observable private _dateValue: Date | string = "";
     @observable private _keyRestrictions: [JSX.Element, string][] = [];
-    @observable private _collapsed: boolean = false;
     @computed private get filterValue() { return Cast(this.props.CollectionView.props.Document.viewSpecScript, ScriptField); }
 
     private _picker: any;
@@ -61,7 +60,6 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro
                     throw new Error("how did you get here, if chrome status is 'disabled' on a collection, a chrome shouldn't even be instantiated!");
                 }
                 else if (chromeStatus === "collapsed") {
-                    this._collapsed = true;
                     if (this.props.collapse) {
                         this.props.collapse(true);
                     }
@@ -163,9 +161,9 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro
 
     @action
     toggleCollapse = () => {
-        this._collapsed = !this._collapsed;
+        this.props.CollectionView.props.Document.chromeStatus = this.props.CollectionView.props.Document.chromeStatus === "enabled" ? "collapsed" : "enabled";
         if (this.props.collapse) {
-            this.props.collapse(this._collapsed);
+            this.props.collapse(this.props.CollectionView.props.Document.chromeStatus !== "enabled");
         }
     }
 
@@ -218,16 +216,17 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro
     }
 
     render() {
+        let collapsed = this.props.CollectionView.props.Document.chromeStatus !== "enabled";
         return (
-            <div className="collectionViewChrome-cont" style={{ top: this._collapsed ? -70 : 0 }}>
+            <div className="collectionViewChrome-cont" style={{ top: collapsed ? -70 : 0 }}>
                 <div className="collectionViewChrome">
                     <div className="collectionViewBaseChrome">
                         <button className="collectionViewBaseChrome-collapse"
                             style={{
-                                top: this._collapsed ? 70 : 10,
-                                transform: `rotate(${this._collapsed ? 180 : 0}deg) scale(${this._collapsed ? 0.5 : 1}) translate(${this._collapsed ? "-100%, -100%" : "0, 0"})`,
-                                opacity: (this._collapsed && !this.props.CollectionView.props.isSelected()) ? 0 : 0.9,
-                                left: (this._collapsed ? 0 : "unset"),
+                                top: collapsed ? 70 : 10,
+                                transform: `rotate(${collapsed ? 180 : 0}deg) scale(${collapsed ? 0.5 : 1}) translate(${collapsed ? "-100%, -100%" : "0, 0"})`,
+                                opacity: (collapsed && !this.props.CollectionView.props.isSelected()) ? 0 : 0.9,
+                                left: (collapsed ? 0 : "unset"),
                             }}
                             title="Collapse collection chrome" onClick={this.toggleCollapse}>
                             <FontAwesomeIcon icon="caret-up" size="2x" />
@@ -243,7 +242,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro
                             <option className="collectionViewBaseChrome-viewOption" onPointerDown={stopPropagation} value="5">Stacking View</option>
                             <option className="collectionViewBaseChrome-viewOption" onPointerDown={stopPropagation} value="6">Masonry View</option>
                         </select>
-                        <div className="collectionViewBaseChrome-viewSpecs" style={{ display: this._collapsed ? "none" : "grid" }}>
+                        <div className="collectionViewBaseChrome-viewSpecs" style={{ display: collapsed ? "none" : "grid" }}>
                             <input className="collectionViewBaseChrome-viewSpecsInput"
                                 placeholder="FILTER DOCUMENTS"
                                 value={this.filterValue ? this.filterValue.script.originalScript : ""}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 30010e826..0501bf929 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -816,17 +816,8 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
 
     onContextMenu = (e: React.MouseEvent) => {
         let layoutItems: ContextMenuProps[] = [];
-        layoutItems.push({
-            description: `${this.fitToBox ? "Unset" : "Set"} Fit To Container`,
-            event: this.fitToContainer,
-            icon: !this.fitToBox ? "expand-arrows-alt" : "compress-arrows-alt"
-        });
-        layoutItems.push({
-            description: "reset view", event: () => {
-                this.props.Document.panX = this.props.Document.panY = 0;
-                this.props.Document.scale = 1;
-            }, icon: "compress-arrows-alt"
-        });
+        layoutItems.push({ description: `${this.fitToBox ? "Unset" : "Set"} Fit To Container`, event: this.fitToContainer, icon: !this.fitToBox ? "expand-arrows-alt" : "compress-arrows-alt" });
+        layoutItems.push({ description: "reset view", event: () => { this.props.Document.panX = this.props.Document.panY = 0; this.props.Document.scale = 1; }, icon: "compress-arrows-alt" });
         layoutItems.push({
             description: `${this.props.Document.useClusters ? "Uncluster" : "Use Clusters"}`,
             event: async () => {
@@ -841,50 +832,13 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
             event: async () => this.props.Document.clusterOverridesDefaultBackground = !this.props.Document.clusterOverridesDefaultBackground,
             icon: !this.props.Document.useClusters ? "chalkboard" : "chalkboard"
         });
-        layoutItems.push({
-            description: "Arrange contents in grid",
-            event: this.arrangeContents,
-            icon: "table"
-        });
-        ContextMenu.Instance.addItem({
-            description: "Layout...",
-            subitems: layoutItems,
-            icon: "compass"
-        });
-        ContextMenu.Instance.addItem({
-            description: "Analyze Strokes",
-            event: this.analyzeStrokes,
-            icon: "paint-brush"
-        });
-        ContextMenu.Instance.addItem({
-            description: "Import document", icon: "upload", event: () => {
-                const input = document.createElement("input");
-                input.type = "file";
-                input.accept = ".zip";
-                input.onchange = async _e => {
-                    const files = input.files;
-                    if (!files) return;
-                    const file = files[0];
-                    let formData = new FormData();
-                    formData.append('file', file);
-                    formData.append('remap', "true");
-                    const upload = Utils.prepend("/uploadDoc");
-                    const response = await fetch(upload, { method: "POST", body: formData });
-                    const json = await response.json();
-                    if (json === "error") {
-                        return;
-                    }
-                    const doc = await DocServer.GetRefField(json);
-                    if (!doc || !(doc instanceof Doc)) {
-                        return;
-                    }
-                    const [x, y] = this.props.ScreenToLocalTransform().transformPoint(e.pageX, e.pageY);
-                    doc.x = x, doc.y = y;
-                    this.addDocument(doc, false);
-                };
-                input.click();
-            }
-        });
+        layoutItems.push({ description: "Arrange contents in grid", event: this.arrangeContents, icon: "table" });
+        ContextMenu.Instance.addItem({ description: "Layout...", subitems: layoutItems, icon: "compass" });
+
+        let existingAnalyze = ContextMenu.Instance.findByDescription("Analyzers...");
+        let analyzers: ContextMenuProps[] = existingAnalyze && "subitems" in existingAnalyze ? existingAnalyze.subitems : [];
+        analyzers.push({ description: "Analyze Strokes", event: this.analyzeStrokes, icon: "paint-brush" });
+        !existingAnalyze && ContextMenu.Instance.addItem({ description: "Analyzers...", subitems: analyzers, icon: "hand-point-right" });
     }
 
 
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index 2466f13f6..c73e960d8 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -85,8 +85,7 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & {
         let list = {
             ...OmitKeys(this.props, ['parentActive'], (obj: any) => obj.active = this.props.parentActive).omit,
             Document: this.layoutDoc,
-            DataDoc: this.dataDoc,
-            onClick: this.props.onClick
+            DataDoc: this.dataDoc
         };
         return { props: list };
     }
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index b8e2eb436..a702ab80e 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -8,13 +8,15 @@ import { Copy, Id } from '../../../new_fields/FieldSymbols';
 import { List } from "../../../new_fields/List";
 import { ObjectField } from "../../../new_fields/ObjectField";
 import { createSchema, listSpec, makeInterface } from "../../../new_fields/Schema";
-import { BoolCast, Cast, FieldValue, NumCast, StrCast, PromiseValue } from "../../../new_fields/Types";
+import { ScriptField } from '../../../new_fields/ScriptField';
+import { BoolCast, Cast, FieldValue, NumCast, StrCast } from "../../../new_fields/Types";
 import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils";
 import { RouteStore } from '../../../server/RouteStore';
 import { emptyFunction, returnTrue, Utils } from "../../../Utils";
 import { DocServer } from "../../DocServer";
 import { Docs, DocUtils } from "../../documents/Documents";
 import { ClientUtils } from '../../util/ClientUtils';
+import { DictationManager } from '../../util/DictationManager';
 import { DocumentManager } from "../../util/DocumentManager";
 import { DragManager, dropActionType } from "../../util/DragManager";
 import { LinkManager } from '../../util/LinkManager';
@@ -29,20 +31,16 @@ import { ContextMenu } from "../ContextMenu";
 import { ContextMenuProps } from '../ContextMenuItem';
 import { DocComponent } from "../DocComponent";
 import { EditableView } from '../EditableView';
+import { MainView } from '../MainView';
 import { OverlayView } from '../OverlayView';
 import { PresentationView } from "../presentationview/PresentationView";
+import { ScriptBox } from '../ScriptBox';
 import { ScriptingRepl } from '../ScriptingRepl';
 import { Template } from "./../Templates";
 import { DocumentContentsView } from "./DocumentContentsView";
 import "./DocumentView.scss";
 import { FormattedTextBox } from './FormattedTextBox';
 import React = require("react");
-import { DictationManager } from '../../util/DictationManager';
-import { MainView } from '../MainView';
-import { ScriptBox } from '../ScriptBox';
-import { CompileScript } from '../../util/Scripting';
-import { DocumentIconContainer } from './DocumentIcon';
-import { ScriptField } from '../../../new_fields/ScriptField';
 const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this?
 
 library.add(fa.faTrash);
@@ -297,8 +295,8 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     onClick = async (e: React.MouseEvent) => {
         if (e.nativeEvent.cancelBubble) return; // needed because EditableView may stopPropagation which won't apparently stop this event from firing.
         e.stopPropagation();
-        if (this.onClickHandler) {
-            this.onClickHandler.script.run({ this: this.props.Document });
+        if (this.onClickHandler && this.onClickHandler.script) {
+            this.onClickHandler.script.run({ this: this.props.Document.isTemplate && this.props.DataDoc ? this.props.DataDoc : this.props.Document });
             e.preventDefault();
             return;
         }
@@ -573,37 +571,11 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         subitems.push({ description: "Open Right Alias", event: () => this.props.addDocTab && this.props.addDocTab(Doc.MakeAlias(this.props.Document), this.dataDoc, "onRight"), icon: "caret-square-right" });
         subitems.push({ description: "Open Fields", event: this.fieldsClicked, icon: "layer-group" });
         cm.addItem({ description: "Open...", subitems: subitems, icon: "external-link-alt" });
-        cm.addItem({ description: BoolCast(this.props.Document.ignoreAspect, false) || !this.props.Document.nativeWidth || !this.props.Document.nativeHeight ? "Freeze" : "Unfreeze", event: this.freezeNativeDimensions, icon: "snowflake" });
-        cm.addItem({ description: "Pin to Presentation", event: () => PresentationView.Instance.PinDoc(this.props.Document), icon: "map-pin" });
-        cm.addItem({ description: BoolCast(this.props.Document.lockedPosition) ? "Unlock Position" : "Lock Position", event: this.toggleLockPosition, icon: BoolCast(this.props.Document.lockedPosition) ? "unlock" : "lock" });
-        cm.addItem({ description: "Transcribe Speech", event: this.listen, icon: "microphone" });
-        cm.addItem({
-            description: "Edit OnClick script", icon: "edit", event: () => {
-                let overlayDisposer: () => void = emptyFunction;
-                const script = this.Document.onClick;
-                let originalText: string | undefined = undefined;
-                if (script) originalText = script.script.originalScript;
-                // tslint:disable-next-line: no-unnecessary-callback-wrapper
-                let scriptingBox = <ScriptBox initialText={originalText} onCancel={() => overlayDisposer()} onSave={(text, onError) => {
-                    const script = CompileScript(text, {
-                        params: { this: Doc.name },
-                        typecheck: false,
-                        editable: true,
-                        transformer: DocumentIconContainer.getTransformer()
-                    });
-                    if (!script.compiled) {
-                        onError(script.errors.map(error => error.messageText).join("\n"));
-                        return;
-                    }
-                    this.Document.onClick = new ScriptField(script);
-                    overlayDisposer();
-                }} showDocumentIcons />;
-                overlayDisposer = OverlayView.Instance.addWindow(scriptingBox, { x: 400, y: 200, width: 500, height: 400, title: `${this.Document.title || ""} OnClick` });
-            }
-        });
-        let makes: ContextMenuProps[] = [];
+        let existingMake = ContextMenu.Instance.findByDescription("Make...");
+        let makes: ContextMenuProps[] = existingMake && "subitems" in existingMake ? existingMake.subitems : [];
         makes.push({ description: this.props.Document.isBackground ? "Remove Background" : "Make Background", event: this.makeBackground, icon: BoolCast(this.props.Document.lockedPosition) ? "unlock" : "lock" });
         makes.push({ description: this.props.Document.isButton ? "Remove Button" : "Make Button", event: this.makeBtnClicked, icon: "concierge-bell" });
+        makes.push({ description: "Edit OnClick script", icon: "edit", event: () => ScriptBox.EditClickScript(this.props.Document, "onClick") });
         makes.push({
             description: "Make Portal", event: () => {
                 let portal = Docs.Create.FreeformDocument([], { width: this.props.Document[WidthSym]() + 10, height: this.props.Document[HeightSym](), title: this.props.Document.title + ".portal" });
@@ -618,15 +590,19 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
 
             }, icon: "window-restore"
         });
-        cm.addItem({ description: "Make...", subitems: makes, icon: "hand-point-right" });
-        if (this.props.Document.detailedLayout && !this.props.Document.isTemplate) {
-            cm.addItem({ description: "Toggle detail", event: () => Doc.ToggleDetailLayout(this.props.Document), icon: "image" });
-        }
-        cm.addItem({ description: "Add Repl", icon: "laptop-code", event: () => OverlayView.Instance.addWindow(<ScriptingRepl />, { x: 300, y: 100, width: 200, height: 200, title: "Scripting REPL" }) });
+        !existingMake && cm.addItem({ description: "Make...", subitems: makes, icon: "hand-point-right" });
         let existing = ContextMenu.Instance.findByDescription("Layout...");
         let layoutItems: ContextMenuProps[] = existing && "subitems" in existing ? existing.subitems : [];
+
+        layoutItems.push({ description: `${this.props.Document.chromeStatus !== "disabled" ? "Hide" : "Show"} Chrome`, event: () => this.props.Document.chromeStatus = (this.props.Document.chromeStatus !== "disabled" ? "disabled" : "enabled"), icon: "project-diagram" });
+        layoutItems.push({ description: `${this.props.Document.autoHeight ? "Variable Height" : "Auto Height"}`, event: () => this.props.Document.autoHeight = !this.props.Document.autoHeight, icon: "plus" });
+        layoutItems.push({ description: BoolCast(this.props.Document.ignoreAspect, false) || !this.props.Document.nativeWidth || !this.props.Document.nativeHeight ? "Freeze" : "Unfreeze", event: this.freezeNativeDimensions, icon: "snowflake" });
+        layoutItems.push({ description: BoolCast(this.props.Document.lockedPosition) ? "Unlock Position" : "Lock Position", event: this.toggleLockPosition, icon: BoolCast(this.props.Document.lockedPosition) ? "unlock" : "lock" });
         layoutItems.push({ description: "Center View", event: () => this.props.focus(this.props.Document, false), icon: "crosshairs" });
         layoutItems.push({ description: "Zoom to Document", event: () => this.props.focus(this.props.Document, true), icon: "search" });
+        if (this.props.Document.detailedLayout && !this.props.Document.isTemplate) {
+            layoutItems.push({ description: "Toggle detail", event: () => Doc.ToggleDetailLayout(this.props.Document), icon: "image" });
+        }
         !existing && cm.addItem({ description: "Layout...", subitems: layoutItems, icon: "compass" });
         if (!ClientUtils.RELEASE) {
             let copies: ContextMenuProps[] = [];
@@ -634,6 +610,12 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
             copies.push({ description: "Copy ID", event: () => Utils.CopyText(this.props.Document[Id]), icon: "fingerprint" });
             cm.addItem({ description: "Copy...", subitems: copies, icon: "copy" });
         }
+        let existingAnalyze = ContextMenu.Instance.findByDescription("Analyzers...");
+        let analyzers: ContextMenuProps[] = existingAnalyze && "subitems" in existingAnalyze ? existingAnalyze.subitems : [];
+        analyzers.push({ description: "Transcribe Speech", event: this.listen, icon: "microphone" });
+        !existingAnalyze && cm.addItem({ description: "Analyzers...", subitems: analyzers, icon: "hand-point-right" });
+        cm.addItem({ description: "Pin to Presentation", event: () => PresentationView.Instance.PinDoc(this.props.Document), icon: "map-pin" });
+        cm.addItem({ description: "Add Repl", icon: "laptop-code", event: () => OverlayView.Instance.addWindow(<ScriptingRepl />, { x: 300, y: 100, width: 200, height: 200, title: "Scripting REPL" }) });
         cm.addItem({
             description: "Download document", icon: "download", event: () => {
                 const a = document.createElement("a");
@@ -643,6 +625,36 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                 a.click();
             }
         });
+
+        cm.addItem({
+            description: "Import document", icon: "upload", event: () => {
+                const input = document.createElement("input");
+                input.type = "file";
+                input.accept = ".zip";
+                input.onchange = async _e => {
+                    const files = input.files;
+                    if (!files) return;
+                    const file = files[0];
+                    let formData = new FormData();
+                    formData.append('file', file);
+                    formData.append('remap', "true");
+                    const upload = Utils.prepend("/uploadDoc");
+                    const response = await fetch(upload, { method: "POST", body: formData });
+                    const json = await response.json();
+                    if (json === "error") {
+                        return;
+                    }
+                    const doc = await DocServer.GetRefField(json);
+                    if (!doc || !(doc instanceof Doc)) {
+                        return;
+                    }
+                    const [x, y] = this.props.ScreenToLocalTransform().transformPoint(e.pageX, e.pageY);
+                    doc.x = x, doc.y = y;
+                    this.props.addDocument && this.props.addDocument(doc, false);
+                };
+                input.click();
+            }
+        });
         cm.addItem({ description: "Delete", event: this.deleteClicked, icon: "trash" });
         type User = { email: string, userDocumentId: string };
         let usersMenu: ContextMenuProps[] = [];
@@ -715,7 +727,10 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         return this.props.Document.layout instanceof Doc ? this.props.Document.layout : this.props.Document;
     }
 
+    @computed get brushedDegree() { return Doc.IsBrushedDegree(this.layoutDoc); }
+
     render() {
+        trace();
         let backgroundColor = this.layoutDoc.isBackground || (this.props.ContainingCollectionView && this.props.ContainingCollectionView.props.Document.clusterOverridesDefaultBackground && this.layoutDoc.backgroundColor === this.layoutDoc.defaultBackgroundColor) ?
             this.props.backgroundColor(this.layoutDoc) || StrCast(this.layoutDoc.backgroundColor) :
             StrCast(this.layoutDoc.backgroundColor) || this.props.backgroundColor(this.layoutDoc);
@@ -733,7 +748,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
             });
         }
         let showTextTitle = showTitle && StrCast(this.layoutDoc.layout).startsWith("<FormattedTextBox") ? showTitle : undefined;
-        let brushDegree = Doc.IsBrushedDegree(this.layoutDoc);
+        let brushDegree = 0;//this.brushedDegree;
         return (
             <div className={`documentView-node${this.topMost ? "-topmost" : ""}`}
                 ref={this._mainCont}
@@ -779,7 +794,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                                     height={72}
                                     fontSize={12}
                                     GetValue={() => StrCast((this.layoutDoc.isTemplate || !this.dataDoc ? this.layoutDoc : this.dataDoc)[showTitle!])}
-                                    SetValue={(value: string) => (Doc.GetProto(this.layoutDoc)[showTitle!] = value) ? true : true}
+                                    SetValue={(value: string) => ((this.layoutDoc.isTemplate ? this.layoutDoc : Doc.GetProto(this.layoutDoc))[showTitle!] = value) ? true : true}
                                 />
                             </div>
                         }
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index cf4f7f668..732576328 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -475,6 +475,9 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
     }
 
     onPointerDown = (e: React.PointerEvent): void => {
+        if (this.onClick && e.button === 0) {
+            e.preventDefault();
+        }
         if (e.button === 0 && this.props.isSelected() && !e.altKey && !e.ctrlKey && !e.metaKey) {
             e.stopPropagation();
             if (FormattedTextBox._toolTipTextMenu && FormattedTextBox._toolTipTextMenu.tooltip) {
@@ -643,12 +646,12 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
     }
 
     specificContextMenu = (e: React.MouseEvent): void => {
-        let subitems: ContextMenuProps[] = [];
-        subitems.push({
-            description: BoolCast(this.props.Document.autoHeight) ? "Manual Height" : "Auto Height",
-            event: action(() => Doc.GetProto(this.props.Document).autoHeight = !BoolCast(this.props.Document.autoHeight)), icon: "expand-arrows-alt"
-        });
-        ContextMenu.Instance.addItem({ description: "Text Funcs...", subitems: subitems, icon: "text-height" });
+        // let subitems: ContextMenuProps[] = [];
+        // subitems.push({
+        //     description: BoolCast(this.props.Document.autoHeight) ? "Manual Height" : "Auto Height",
+        //     event: action(() => Doc.GetProto(this.props.Document).autoHeight = !BoolCast(this.props.Document.autoHeight)), icon: "expand-arrows-alt"
+        // });
+        // ContextMenu.Instance.addItem({ description: "Text Funcs...", subitems: subitems, icon: "text-height" });
     }
     render() {
         let self = this;
diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts
index 4cfd7929b..564446bb8 100644
--- a/src/new_fields/Doc.ts
+++ b/src/new_fields/Doc.ts
@@ -516,6 +516,8 @@ export namespace Doc {
         otherdoc.miniLayout = StrCast(templateDoc.miniLayout);
         otherdoc.detailedLayout = otherdoc.layout;
         otherdoc.type = DocumentType.TEMPLATE;
+        !templateDoc.nativeWidth && (otherdoc.nativeWidth = 0);
+        !templateDoc.nativeHeight && (otherdoc.nativeHeight = 0);
         return otherdoc;
     }
     export function ApplyTemplateTo(templateDoc: Doc, target: Doc, targetData?: Doc) {
@@ -534,6 +536,8 @@ export namespace Doc {
             target.miniLayout = StrCast(templateDoc.miniLayout);
             target.detailedLayout = target.layout;
         }
+        !templateDoc.nativeWidth && (target.nativeWidth = 0);
+        !templateDoc.nativeHeight && (target.nativeHeight = 0);
     }
 
     export function MakeTemplate(fieldTemplate: Doc, metaKey: string, templateDataDoc: Doc) {
@@ -610,4 +614,7 @@ export namespace Doc {
 }
 Scripting.addGlobal(function renameAlias(doc: any, n: any) {
     return StrCast(doc.title).replace(/\([0-9]*\)/, "") + `(${n})`;
+});
+Scripting.addGlobal(function getProto(doc: any) {
+    return Doc.GetProto(doc);
 });
\ No newline at end of file
diff --git a/src/new_fields/Types.ts b/src/new_fields/Types.ts
index 09cbff25e..0ca35fab2 100644
--- a/src/new_fields/Types.ts
+++ b/src/new_fields/Types.ts
@@ -2,6 +2,7 @@ import { Field, Opt, FieldResult, Doc } from "./Doc";
 import { List } from "./List";
 import { RefField } from "./RefField";
 import { DateField } from "./DateField";
+import { ScriptField } from "./ScriptField";
 
 export type ToType<T extends InterfaceValue> =
     T extends "string" ? string :
@@ -86,6 +87,9 @@ export function BoolCast(field: FieldResult, defaultVal: boolean | null = false)
 export function DateCast(field: FieldResult) {
     return Cast(field, DateField, null);
 }
+export function ScriptCast(field: FieldResult) {
+    return Cast(field, ScriptField, null);
+}
 
 type WithoutList<T extends Field> = T extends List<infer R> ? (R extends RefField ? (R | Promise<R>)[] : R[]) : T;
 
-- 
cgit v1.2.3-70-g09d2


From 2b829d1028a61869858ecd48e2f1801819e17488 Mon Sep 17 00:00:00 2001
From: Sam Wilkins <samwilkins333@gmail.com>
Date: Tue, 13 Aug 2019 22:15:47 -0400
Subject: robust google doc export api and cleanup

---
 .../apis/google_docs/GoogleApiClientUtils.ts       | 185 ++++++++++++---------
 src/client/views/MainView.tsx                      |  11 +-
 src/client/views/nodes/FormattedTextBox.tsx        |  24 ++-
 src/new_fields/RichTextField.ts                    |  13 ++
 src/server/index.ts                                |  25 ++-
 5 files changed, 162 insertions(+), 96 deletions(-)

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

diff --git a/src/client/apis/google_docs/GoogleApiClientUtils.ts b/src/client/apis/google_docs/GoogleApiClientUtils.ts
index 5e974b2e7..dda36f05a 100644
--- a/src/client/apis/google_docs/GoogleApiClientUtils.ts
+++ b/src/client/apis/google_docs/GoogleApiClientUtils.ts
@@ -1,7 +1,8 @@
 import { docs_v1 } from "googleapis";
 import { PostToServer } from "../../../Utils";
 import { RouteStore } from "../../../server/RouteStore";
-import { Opt } from "../../../new_fields/Doc";
+import { Opt, Doc } from "../../../new_fields/Doc";
+import { isArray } from "util";
 
 export namespace GoogleApiClientUtils {
 
@@ -9,15 +10,12 @@ export namespace GoogleApiClientUtils {
 
         export enum Actions {
             Create = "create",
-            Retrieve = "retrieve"
+            Retrieve = "retrieve",
+            Update = "update"
         }
 
         export namespace Utils {
 
-            export const fromRgb = (red: number, green: number, blue: number) => {
-                return { color: { rgbColor: { red, green, blue } } };
-            };
-
             export const extractText = (document: docs_v1.Schema$Document, removeNewlines = false) => {
                 let fragments: string[] = [];
                 if (document.body && document.body.content) {
@@ -36,55 +34,36 @@ export namespace GoogleApiClientUtils {
                 return removeNewlines ? text.ReplaceAll("\n", "") : text;
             };
 
-        }
-
-        export const ExampleDocumentSchema = {
-            title: "This is a Google Doc Created From Dash Web",
-            body: {
-                content: [
-                    {
-                        endIndex: 1,
-                        sectionBreak: {
-                            sectionStyle: {
-                                columnSeparatorStyle: "NONE",
-                                contentDirection: "LEFT_TO_RIGHT"
+            export const EndOf = (schema: docs_v1.Schema$Document): Opt<number> => {
+                if (schema.body && schema.body.content) {
+                    let paragraphs = schema.body.content.filter(el => el.paragraph);
+                    if (paragraphs.length) {
+                        let target = paragraphs[paragraphs.length - 1];
+                        if (target.paragraph && target.paragraph.elements) {
+                            length = target.paragraph.elements.length;
+                            if (length) {
+                                let final = target.paragraph.elements[length - 1];
+                                return final.endIndex ? final.endIndex - 1 : undefined;
                             }
                         }
-                    },
-                    {
-                        paragraph: {
-                            elements: [
-                                {
-                                    textRun: {
-                                        content: "And this is its bold, blue text!!!\n",
-                                        textStyle: {
-                                            bold: true,
-                                            backgroundColor: Utils.fromRgb(0, 0, 1)
-                                        }
-                                    }
-                                }
-                            ]
-                        }
-                    },
-                    {
-                        paragraph: {
-                            elements: [
-                                {
-                                    textRun: {
-                                        content: "And this is its bold, blue text!!!\n",
-                                        textStyle: {
-                                            bold: true,
-                                            backgroundColor: Utils.fromRgb(0, 0, 1)
-                                        }
-                                    }
-                                }
-                            ]
-                        }
-                    },
+                    }
+                }
+            };
 
-                ] as docs_v1.Schema$StructuralElement[]
-            }
-        } as docs_v1.Schema$Document;
+        }
+
+        export interface ReadOptions {
+            documentId: string;
+            removeNewlines?: boolean;
+        }
+
+        export interface WriteOptions {
+            documentId?: string;
+            title?: string;
+            content: string | string[];
+            index?: number;
+            store?: { receiver: Doc, key: string };
+        }
 
         /**
          * After following the authentication routine, which connects this API call to the current signed in account
@@ -96,45 +75,95 @@ export namespace GoogleApiClientUtils {
          * actual document body and its styling!
          * @returns the documentId of the newly generated document, or undefined if the creation process fails.
          */
-        export const Create = async (schema?: docs_v1.Schema$Document): Promise<string | undefined> => {
+        const Create = async (title?: string): Promise<string | undefined> => {
             let path = RouteStore.googleDocs + Actions.Create;
-            let parameters = { requestBody: schema || ExampleDocumentSchema };
-            let generatedId: string | undefined;
+            let parameters = {
+                requestBody: {
+                    title: title || `Dash Export (${new Date().toDateString()})`
+                }
+            };
             try {
-                generatedId = await PostToServer(path, parameters);
-            } catch (e) {
-                console.error(e);
-                generatedId = undefined;
-            } finally {
-                return generatedId;
+                let schema: docs_v1.Schema$Document = await PostToServer(path, parameters);
+                return schema.documentId;
+            } catch {
+                return undefined;
             }
         };
 
-        export interface ReadOptions {
-            documentId: string;
-            removeNewlines?: boolean;
-        }
+        const Retrieve = async (documentId: string): Promise<docs_v1.Schema$Document | undefined> => {
+            let path = RouteStore.googleDocs + Actions.Retrieve;
+            let parameters = {
+                documentId
+            };
+            try {
+                let schema: docs_v1.Schema$Document = await PostToServer(path, parameters);
+                return schema;
+            } catch {
+                return undefined;
+            }
+        };
+
+        const Update = async (documentId: string, requests: docs_v1.Schema$Request[]): Promise<docs_v1.Schema$BatchUpdateDocumentResponse | undefined> => {
+            let path = RouteStore.googleDocs + Actions.Update;
+            let parameters = {
+                documentId,
+                requestBody: {
+                    requests
+                }
+            };
+            try {
+                let replies: docs_v1.Schema$BatchUpdateDocumentResponse = await PostToServer(path, parameters);
+                console.log(replies);
+                return replies;
+            } catch {
+                return undefined;
+            }
+        };
 
-        export const Read = async (options: ReadOptions): Promise<Opt<string>> => {
+        export const Read = async (options: ReadOptions): Promise<string | undefined> => {
             return Retrieve(options.documentId).then(schema => {
                 return schema ? Utils.extractText(schema, options.removeNewlines) : undefined;
             });
         };
 
-        export const Retrieve = async (documentId: string): Promise<Opt<docs_v1.Schema$Document>> => {
-            let path = RouteStore.googleDocs + Actions.Retrieve;
-            let parameters = { documentId };
-            let schema: Opt<docs_v1.Schema$Document>;
-            try {
-                schema = await PostToServer(path, parameters);
-            } catch (e) {
-                console.error(e);
-                schema = undefined;
-            } finally {
-                return schema;
-            }
+        export const ReadLines = async (options: ReadOptions) => {
+            return Retrieve(options.documentId).then(schema => {
+                if (!schema) {
+                    return undefined;
+                }
+                let lines = Utils.extractText(schema).split("\n");
+                return options.removeNewlines ? lines.filter(line => line.length) : lines;
+            });
         };
 
+        export const Write = async (options: WriteOptions): Promise<docs_v1.Schema$BatchUpdateDocumentResponse | undefined> => {
+            let target = options.documentId;
+            if (!target) {
+                if (!(target = await Create(options.title))) {
+                    return undefined;
+                }
+            }
+            let index = options.index;
+            if (!index) {
+                let schema = await Retrieve(target);
+                if (!schema || !(index = Utils.EndOf(schema))) {
+                    return undefined;
+                }
+            }
+            let text = options.content;
+            let request = {
+                insertText: {
+                    text: isArray(text) ? text.join("\n") : text,
+                    location: { index }
+                }
+            };
+            return Update(target, [request]).then(res => {
+                if (res && options.store) {
+                    options.store.receiver[options.store.key] = res.documentId;
+                }
+                return res;
+            });
+        };
 
     }
 
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 705eacc0c..7b15e9624 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -87,11 +87,6 @@ export class MainView extends React.Component {
             if (!("presentationView" in doc)) {
                 doc.presentationView = new List<Doc>([Docs.Create.TreeDocument([], { title: "Presentation" })]);
             }
-            if (!("googleDocId" in doc)) {
-                GoogleApiClientUtils.Docs.Create().then(id => {
-                    id && (doc.googleDocId = id);
-                });
-            }
             CurrentUserUtils.UserDocument.activeWorkspace = doc;
         }
     }
@@ -158,9 +153,9 @@ export class MainView extends React.Component {
         reaction(() => this.mainContainer, () => {
             let main = this.mainContainer, documentId;
             if (main && (documentId = StrCast(main.googleDocId))) {
-                GoogleApiClientUtils.Docs.Read({ documentId }).then(text => {
-                    text && Utils.CopyText(text);
-                    console.log(text);
+                let options = { documentId, removeNewlines: true };
+                GoogleApiClientUtils.Docs.ReadLines(options).then(lines => {
+                    console.log(lines);
                 });
             }
         });
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 44b5d2c21..8c2af7c9e 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -1,5 +1,5 @@
 import { library } from '@fortawesome/fontawesome-svg-core';
-import { faEdit, faSmile, faTextHeight } from '@fortawesome/free-solid-svg-icons';
+import { faEdit, faSmile, faTextHeight, faUpload } from '@fortawesome/free-solid-svg-icons';
 import { action, IReactionDisposer, observable, reaction, runInAction, computed, Lambda, trace } from "mobx";
 import { observer } from "mobx-react";
 import { baseKeymap } from "prosemirror-commands";
@@ -38,9 +38,10 @@ import { For } from 'babel-types';
 import { DateField } from '../../../new_fields/DateField';
 import { Utils } from '../../../Utils';
 import { MainOverlayTextBox } from '../MainOverlayTextBox';
+import { GoogleApiClientUtils } from '../../apis/google_docs/GoogleApiClientUtils';
 
 library.add(faEdit);
-library.add(faSmile, faTextHeight);
+library.add(faSmile, faTextHeight, faUpload);
 
 // FormattedTextBox: Displays an editable plain text node that maps to a specified Key of a Document
 //
@@ -58,6 +59,8 @@ const richTextSchema = createSchema({
     documentText: "string"
 });
 
+const googleDocKey = "googleDocId";
+
 type RichTextDocument = makeInterface<[typeof richTextSchema]>;
 const RichTextDocument = makeInterface(richTextSchema);
 
@@ -661,7 +664,24 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
             event: action(() => Doc.GetProto(this.props.Document).autoHeight = !BoolCast(this.props.Document.autoHeight)), icon: "expand-arrows-alt"
         });
         ContextMenu.Instance.addItem({ description: "Text Funcs...", subitems: subitems, icon: "text-height" });
+        if (!(googleDocKey in Doc.GetProto(this.props.Document))) {
+            ContextMenu.Instance.addItem({ description: "Export to Google Doc...", event: this.exportToGoogleDoc, icon: "upload" });
+        }
     }
+
+    exportToGoogleDoc = () => {
+        let dataDoc = Doc.GetProto(this.props.Document);
+        let data = Cast(dataDoc.data, RichTextField);
+        let content: string | undefined;
+        if (data && (content = data.plainText())) {
+            GoogleApiClientUtils.Docs.Write({
+                title: StrCast(dataDoc.title),
+                store: { receiver: dataDoc, key: googleDocKey },
+                content
+            });
+        }
+    }
+
     render() {
         let self = this;
         let style = this.props.isOverlay ? "scroll" : "hidden";
diff --git a/src/new_fields/RichTextField.ts b/src/new_fields/RichTextField.ts
index 89799b2af..dc66813e0 100644
--- a/src/new_fields/RichTextField.ts
+++ b/src/new_fields/RichTextField.ts
@@ -9,6 +9,7 @@ import { scriptingGlobal } from "../client/util/Scripting";
 export class RichTextField extends ObjectField {
     @serializable(true)
     readonly Data: string;
+    private Extractor = /,\"text\":\"([^\"\}]*)\"\}/g;
 
     constructor(data: string) {
         super();
@@ -22,4 +23,16 @@ export class RichTextField extends ObjectField {
     [ToScriptString]() {
         return `new RichTextField("${this.Data}")`;
     }
+
+    plainText = () => {
+        let contents = "";
+        let matches: RegExpExecArray | null;
+        let considering = this.Data;
+        while ((matches = this.Extractor.exec(considering)) !== null) {
+            contents += matches[1];
+            considering = considering.substring(matches.index + matches[0].length);
+            this.Extractor.lastIndex = 0;
+        }
+        return contents.length ? contents : undefined;
+    }
 }
\ No newline at end of file
diff --git a/src/server/index.ts b/src/server/index.ts
index 4ccb61681..abaa29658 100644
--- a/src/server/index.ts
+++ b/src/server/index.ts
@@ -42,6 +42,7 @@ import AdmZip from 'adm-zip';
 import * as YoutubeApi from "./apis/youtube/youtubeApiSample";
 import { Response } from 'express-serve-static-core';
 import { GoogleApiServerUtils } from "./apis/google/GoogleApiServerUtils";
+import { GaxiosResponse } from 'gaxios';
 const MongoStore = require('connect-mongo')(session);
 const mongoose = require('mongoose');
 const probe = require("probe-image-size");
@@ -170,6 +171,13 @@ const read_text_file = (relativePath: string) => {
     });
 };
 
+const write_text_file = (relativePath: string, contents: any) => {
+    let target = path.join(__dirname, relativePath);
+    return new Promise<void>((resolve, reject) => {
+        fs.writeFile(target, contents, (err) => err ? reject(err) : resolve());
+    });
+};
+
 app.get("/version", (req, res) => {
     exec('"C:\\Program Files\\Git\\bin\\git.exe" rev-parse HEAD', (err, stdout, stderr) => {
         if (err) {
@@ -790,21 +798,22 @@ const credentials = path.join(__dirname, "./credentials/google_docs_credentials.
 const token = path.join(__dirname, "./credentials/google_docs_token.json");
 
 app.post(RouteStore.googleDocs + ":action", (req, res) => {
-    let parameters = req.body;
-
     GoogleApiServerUtils.Docs.GetEndpoint({ credentials, token }).then(endpoint => {
-        let results: Promise<any> | undefined;
+        let results: Promise<GaxiosResponse> | undefined;
+        let documents = endpoint.documents;
+        let parameters = req.body;
         switch (req.params.action) {
             case "create":
-                results = endpoint.documents.create(parameters).then(generated => generated.data.documentId);
+                results = documents.create(parameters);
                 break;
             case "retrieve":
-                results = endpoint.documents.get(parameters).then(response => response.data);
+                results = documents.get(parameters);
+                break;
+            case "update":
+                results = documents.batchUpdate(parameters);
                 break;
-            default:
-                results = undefined;
         }
-        results && results.then(final => res.send(final));
+        !results ? res.send(undefined) : results.then(response => res.send(response.data));
     });
 });
 
-- 
cgit v1.2.3-70-g09d2


From dc766185075b5861686c68a704a8e49213eacbc6 Mon Sep 17 00:00:00 2001
From: Sam Wilkins <samwilkins333@gmail.com>
Date: Wed, 14 Aug 2019 01:00:29 -0400
Subject: cleanup and streamlined / robust type requirements

---
 .../apis/google_docs/GoogleApiClientUtils.ts       | 88 +++++++++++-----------
 src/client/views/MainView.tsx                      | 12 ---
 src/client/views/nodes/FormattedTextBox.tsx        | 20 ++---
 src/new_fields/RichTextField.ts                    |  2 +-
 4 files changed, 58 insertions(+), 64 deletions(-)

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

diff --git a/src/client/apis/google_docs/GoogleApiClientUtils.ts b/src/client/apis/google_docs/GoogleApiClientUtils.ts
index dda36f05a..f4fb87e0b 100644
--- a/src/client/apis/google_docs/GoogleApiClientUtils.ts
+++ b/src/client/apis/google_docs/GoogleApiClientUtils.ts
@@ -17,32 +17,32 @@ export namespace GoogleApiClientUtils {
         export namespace Utils {
 
             export const extractText = (document: docs_v1.Schema$Document, removeNewlines = false) => {
-                let fragments: string[] = [];
+                const fragments: string[] = [];
                 if (document.body && document.body.content) {
-                    for (let element of document.body.content) {
+                    for (const element of document.body.content) {
                         if (element.paragraph && element.paragraph.elements) {
-                            for (let inner of element.paragraph.elements) {
+                            for (const inner of element.paragraph.elements) {
                                 if (inner && inner.textRun) {
-                                    let fragment = inner.textRun.content;
+                                    const fragment = inner.textRun.content;
                                     fragment && fragments.push(fragment);
                                 }
                             }
                         }
                     }
                 }
-                let text = fragments.join("");
+                const text = fragments.join("");
                 return removeNewlines ? text.ReplaceAll("\n", "") : text;
             };
 
             export const EndOf = (schema: docs_v1.Schema$Document): Opt<number> => {
                 if (schema.body && schema.body.content) {
-                    let paragraphs = schema.body.content.filter(el => el.paragraph);
+                    const paragraphs = schema.body.content.filter(el => el.paragraph);
                     if (paragraphs.length) {
-                        let target = paragraphs[paragraphs.length - 1];
+                        const target = paragraphs[paragraphs.length - 1];
                         if (target.paragraph && target.paragraph.elements) {
                             length = target.paragraph.elements.length;
                             if (length) {
-                                let final = target.paragraph.elements[length - 1];
+                                const final = target.paragraph.elements[length - 1];
                                 return final.endIndex ? final.endIndex - 1 : undefined;
                             }
                         }
@@ -52,17 +52,25 @@ export namespace GoogleApiClientUtils {
 
         }
 
+        export type IdHandler = (id: DocumentId) => any;
+        export interface CreateOptions {
+            handler: IdHandler;
+            // if excluded, will use a default title annotated with the current date
+            title?: string;
+        }
+
         export interface ReadOptions {
             documentId: string;
+            // if exluded, will preserve newlines
             removeNewlines?: boolean;
         }
 
+        export type DocumentId = string;
         export interface WriteOptions {
-            documentId?: string;
-            title?: string;
             content: string | string[];
+            reference: DocumentId | CreateOptions;
+            // if excluded, will compute the last index of the document and append the content there
             index?: number;
-            store?: { receiver: Doc, key: string };
         }
 
         /**
@@ -70,33 +78,36 @@ export namespace GoogleApiClientUtils {
          * and grants the appropriate permissions, this function programmatically creates an arbitrary Google Doc which
          * should appear in the user's Google Doc library instantaneously.
          * 
-         * @param schema whatever subset of a docs_v1.Schema$Document is required to properly initialize your
-         * Google Doc. This schema defines all aspects of a Google Doc, from the title to headers / footers to the
-         * actual document body and its styling!
+         * @param options the title to assign to the new document, and the information necessary
+         * to store the new documentId returned from the creation process
          * @returns the documentId of the newly generated document, or undefined if the creation process fails.
          */
-        const Create = async (title?: string): Promise<string | undefined> => {
-            let path = RouteStore.googleDocs + Actions.Create;
-            let parameters = {
+        const Create = async (options: CreateOptions): Promise<string | undefined> => {
+            const path = RouteStore.googleDocs + Actions.Create;
+            const parameters = {
                 requestBody: {
-                    title: title || `Dash Export (${new Date().toDateString()})`
+                    title: options.title || `Dash Export (${new Date().toDateString()})`
                 }
             };
             try {
-                let schema: docs_v1.Schema$Document = await PostToServer(path, parameters);
-                return schema.documentId;
+                const schema: docs_v1.Schema$Document = await PostToServer(path, parameters);
+                const generatedId = schema.documentId;
+                if (generatedId) {
+                    options.handler(generatedId);
+                    return generatedId;
+                }
             } catch {
                 return undefined;
             }
         };
 
         const Retrieve = async (documentId: string): Promise<docs_v1.Schema$Document | undefined> => {
-            let path = RouteStore.googleDocs + Actions.Retrieve;
-            let parameters = {
+            const path = RouteStore.googleDocs + Actions.Retrieve;
+            const parameters = {
                 documentId
             };
             try {
-                let schema: docs_v1.Schema$Document = await PostToServer(path, parameters);
+                const schema: docs_v1.Schema$Document = await PostToServer(path, parameters);
                 return schema;
             } catch {
                 return undefined;
@@ -104,16 +115,15 @@ export namespace GoogleApiClientUtils {
         };
 
         const Update = async (documentId: string, requests: docs_v1.Schema$Request[]): Promise<docs_v1.Schema$BatchUpdateDocumentResponse | undefined> => {
-            let path = RouteStore.googleDocs + Actions.Update;
-            let parameters = {
+            const path = RouteStore.googleDocs + Actions.Update;
+            const parameters = {
                 documentId,
                 requestBody: {
                     requests
                 }
             };
             try {
-                let replies: docs_v1.Schema$BatchUpdateDocumentResponse = await PostToServer(path, parameters);
-                console.log(replies);
+                const replies: docs_v1.Schema$BatchUpdateDocumentResponse = await PostToServer(path, parameters);
                 return replies;
             } catch {
                 return undefined;
@@ -131,38 +141,32 @@ export namespace GoogleApiClientUtils {
                 if (!schema) {
                     return undefined;
                 }
-                let lines = Utils.extractText(schema).split("\n");
+                const lines = Utils.extractText(schema).split("\n");
                 return options.removeNewlines ? lines.filter(line => line.length) : lines;
             });
         };
 
         export const Write = async (options: WriteOptions): Promise<docs_v1.Schema$BatchUpdateDocumentResponse | undefined> => {
-            let target = options.documentId;
-            if (!target) {
-                if (!(target = await Create(options.title))) {
-                    return undefined;
-                }
+            let documentId: string | undefined;
+            const ref = options.reference;
+            if (!(documentId = typeof ref === "string" ? ref : await Create(ref))) {
+                return undefined;
             }
             let index = options.index;
             if (!index) {
-                let schema = await Retrieve(target);
+                let schema = await Retrieve(documentId);
                 if (!schema || !(index = Utils.EndOf(schema))) {
                     return undefined;
                 }
             }
-            let text = options.content;
-            let request = {
+            const text = options.content;
+            const request = {
                 insertText: {
                     text: isArray(text) ? text.join("\n") : text,
                     location: { index }
                 }
             };
-            return Update(target, [request]).then(res => {
-                if (res && options.store) {
-                    options.store.receiver[options.store.key] = res.documentId;
-                }
-                return res;
-            });
+            return Update(documentId, [request]);
         };
 
     }
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 7b15e9624..77f0e3d60 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -149,18 +149,6 @@ export class MainView extends React.Component {
         }, { fireImmediately: true });
     }
 
-    componentDidMount() {
-        reaction(() => this.mainContainer, () => {
-            let main = this.mainContainer, documentId;
-            if (main && (documentId = StrCast(main.googleDocId))) {
-                let options = { documentId, removeNewlines: true };
-                GoogleApiClientUtils.Docs.ReadLines(options).then(lines => {
-                    console.log(lines);
-                });
-            }
-        });
-    }
-
     componentWillUnMount() {
         window.removeEventListener("keydown", KeyManager.Instance.handle);
         window.removeEventListener("pointerdown", this.globalPointerDown);
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 8c2af7c9e..50ec27259 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -670,16 +670,18 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
     }
 
     exportToGoogleDoc = () => {
-        let dataDoc = Doc.GetProto(this.props.Document);
-        let data = Cast(dataDoc.data, RichTextField);
-        let content: string | undefined;
-        if (data && (content = data.plainText())) {
-            GoogleApiClientUtils.Docs.Write({
-                title: StrCast(dataDoc.title),
-                store: { receiver: dataDoc, key: googleDocKey },
-                content
-            });
+        const dataDoc = Doc.GetProto(this.props.Document);
+        const data = Cast(dataDoc.data, RichTextField);
+        if (!data) {
+            return;
         }
+        GoogleApiClientUtils.Docs.Write({
+            reference: {
+                title: StrCast(dataDoc.title),
+                handler: id => dataDoc[googleDocKey] = id
+            },
+            content: data.plainText()
+        });
     }
 
     render() {
diff --git a/src/new_fields/RichTextField.ts b/src/new_fields/RichTextField.ts
index dc66813e0..3e8803a34 100644
--- a/src/new_fields/RichTextField.ts
+++ b/src/new_fields/RichTextField.ts
@@ -33,6 +33,6 @@ export class RichTextField extends ObjectField {
             considering = considering.substring(matches.index + matches[0].length);
             this.Extractor.lastIndex = 0;
         }
-        return contents.length ? contents : undefined;
+        return contents;
     }
 }
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2


From 48fcec82fa384ec260a02965f9f78c2e41256dd9 Mon Sep 17 00:00:00 2001
From: Sam Wilkins <samwilkins333@gmail.com>
Date: Wed, 14 Aug 2019 03:41:11 -0400
Subject: clean up and regex improvement

---
 .../apis/google_docs/GoogleApiClientUtils.ts       | 111 ++++++++++++---------
 src/client/views/nodes/FormattedTextBox.tsx        |  15 ++-
 src/new_fields/RichTextField.ts                    |   4 +-
 src/server/index.ts                                |  35 ++++---
 4 files changed, 99 insertions(+), 66 deletions(-)

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

diff --git a/src/client/apis/google_docs/GoogleApiClientUtils.ts b/src/client/apis/google_docs/GoogleApiClientUtils.ts
index f4fb87e0b..c6c7d7bd4 100644
--- a/src/client/apis/google_docs/GoogleApiClientUtils.ts
+++ b/src/client/apis/google_docs/GoogleApiClientUtils.ts
@@ -1,7 +1,7 @@
 import { docs_v1 } from "googleapis";
 import { PostToServer } from "../../../Utils";
 import { RouteStore } from "../../../server/RouteStore";
-import { Opt, Doc } from "../../../new_fields/Doc";
+import { Opt } from "../../../new_fields/Doc";
 import { isArray } from "util";
 
 export namespace GoogleApiClientUtils {
@@ -14,9 +14,42 @@ export namespace GoogleApiClientUtils {
             Update = "update"
         }
 
+        export type DocumentId = string;
+        export type Reference = DocumentId | CreateOptions;
+        export type TextContent = string | string[];
+        export type IdHandler = (id: DocumentId) => any;
+
+        export type CreationResult = Opt<DocumentId>;
+        export type RetrievalResult = Opt<docs_v1.Schema$Document>;
+        export type UpdateResult = Opt<docs_v1.Schema$BatchUpdateDocumentResponse>;
+        export type ReadLinesResult = Opt<string[]>;
+        export type ReadResult = Opt<string>;
+
+        export interface CreateOptions {
+            handler: IdHandler; // callback to process the documentId of the newly created Google Doc
+            title?: string; // if excluded, will use a default title annotated with the current date
+        }
+
+        export interface RetrieveOptions {
+            documentId: DocumentId;
+        }
+
+        export type ReadOptions = RetrieveOptions & { removeNewlines?: boolean };
+
+        export interface WriteOptions {
+            content: TextContent;
+            reference: Reference;
+            index?: number; // if excluded, will compute the last index of the document and append the content there
+        }
+
+        export interface UpdateOptions {
+            documentId: DocumentId;
+            requests: docs_v1.Schema$Request[];
+        }
+
         export namespace Utils {
 
-            export const extractText = (document: docs_v1.Schema$Document, removeNewlines = false) => {
+            export const extractText = (document: docs_v1.Schema$Document, removeNewlines = false): string => {
                 const fragments: string[] = [];
                 if (document.body && document.body.content) {
                     for (const element of document.body.content) {
@@ -34,7 +67,7 @@ export namespace GoogleApiClientUtils {
                 return removeNewlines ? text.ReplaceAll("\n", "") : text;
             };
 
-            export const EndOf = (schema: docs_v1.Schema$Document): Opt<number> => {
+            export const endOf = (schema: docs_v1.Schema$Document): number | undefined => {
                 if (schema.body && schema.body.content) {
                     const paragraphs = schema.body.content.filter(el => el.paragraph);
                     if (paragraphs.length) {
@@ -50,27 +83,8 @@ export namespace GoogleApiClientUtils {
                 }
             };
 
-        }
+            export const initialize = async (reference: Reference) => typeof reference === "string" ? reference : create(reference);
 
-        export type IdHandler = (id: DocumentId) => any;
-        export interface CreateOptions {
-            handler: IdHandler;
-            // if excluded, will use a default title annotated with the current date
-            title?: string;
-        }
-
-        export interface ReadOptions {
-            documentId: string;
-            // if exluded, will preserve newlines
-            removeNewlines?: boolean;
-        }
-
-        export type DocumentId = string;
-        export interface WriteOptions {
-            content: string | string[];
-            reference: DocumentId | CreateOptions;
-            // if excluded, will compute the last index of the document and append the content there
-            index?: number;
         }
 
         /**
@@ -82,7 +96,7 @@ export namespace GoogleApiClientUtils {
          * to store the new documentId returned from the creation process
          * @returns the documentId of the newly generated document, or undefined if the creation process fails.
          */
-        const Create = async (options: CreateOptions): Promise<string | undefined> => {
+        export const create = async (options: CreateOptions): Promise<CreationResult> => {
             const path = RouteStore.googleDocs + Actions.Create;
             const parameters = {
                 requestBody: {
@@ -101,43 +115,40 @@ export namespace GoogleApiClientUtils {
             }
         };
 
-        const Retrieve = async (documentId: string): Promise<docs_v1.Schema$Document | undefined> => {
+        export const retrieve = async (options: RetrieveOptions): Promise<RetrievalResult> => {
             const path = RouteStore.googleDocs + Actions.Retrieve;
-            const parameters = {
-                documentId
-            };
             try {
-                const schema: docs_v1.Schema$Document = await PostToServer(path, parameters);
+                const schema: RetrievalResult = await PostToServer(path, options);
                 return schema;
             } catch {
                 return undefined;
             }
         };
 
-        const Update = async (documentId: string, requests: docs_v1.Schema$Request[]): Promise<docs_v1.Schema$BatchUpdateDocumentResponse | undefined> => {
+        export const update = async (options: UpdateOptions): Promise<UpdateResult> => {
             const path = RouteStore.googleDocs + Actions.Update;
             const parameters = {
-                documentId,
+                documentId: options.documentId,
                 requestBody: {
-                    requests
+                    requests: options.requests
                 }
             };
             try {
-                const replies: docs_v1.Schema$BatchUpdateDocumentResponse = await PostToServer(path, parameters);
+                const replies: UpdateResult = await PostToServer(path, parameters);
                 return replies;
             } catch {
                 return undefined;
             }
         };
 
-        export const Read = async (options: ReadOptions): Promise<string | undefined> => {
-            return Retrieve(options.documentId).then(schema => {
+        export const read = async (options: ReadOptions): Promise<ReadResult> => {
+            return retrieve(options).then(schema => {
                 return schema ? Utils.extractText(schema, options.removeNewlines) : undefined;
             });
         };
 
-        export const ReadLines = async (options: ReadOptions) => {
-            return Retrieve(options.documentId).then(schema => {
+        export const readLines = async (options: ReadOptions): Promise<ReadLinesResult> => {
+            return retrieve(options).then(schema => {
                 if (!schema) {
                     return undefined;
                 }
@@ -146,27 +157,29 @@ export namespace GoogleApiClientUtils {
             });
         };
 
-        export const Write = async (options: WriteOptions): Promise<docs_v1.Schema$BatchUpdateDocumentResponse | undefined> => {
-            let documentId: string | undefined;
-            const ref = options.reference;
-            if (!(documentId = typeof ref === "string" ? ref : await Create(ref))) {
+        export const write = async (options: WriteOptions): Promise<UpdateResult> => {
+            const documentId = await Utils.initialize(options.reference);
+            if (!documentId) {
                 return undefined;
             }
             let index = options.index;
             if (!index) {
-                let schema = await Retrieve(documentId);
-                if (!schema || !(index = Utils.EndOf(schema))) {
+                let schema = await retrieve({ documentId });
+                if (!schema || !(index = Utils.endOf(schema))) {
                     return undefined;
                 }
             }
             const text = options.content;
-            const request = {
-                insertText: {
-                    text: isArray(text) ? text.join("\n") : text,
-                    location: { index }
-                }
+            const updateOptions = {
+                documentId,
+                requests: [{
+                    insertText: {
+                        text: isArray(text) ? text.join("\n") : text,
+                        location: { index }
+                    }
+                }]
             };
-            return Update(documentId, [request]);
+            return update(updateOptions);
         };
 
     }
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 50ec27259..46aed9b2d 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -288,6 +288,19 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
         }
     }
 
+    componentWillMount() {
+        this.pollExportedCounterpart();
+    }
+
+    pollExportedCounterpart = async () => {
+        let dataDoc = Doc.GetProto(this.props.Document);
+        let documentId = StrCast(dataDoc[googleDocKey]);
+        if (documentId) {
+            let contents = await GoogleApiClientUtils.Docs.read({ documentId });
+            contents ? console.log(contents) : delete dataDoc[googleDocKey];
+        }
+    }
+
     componentDidMount() {
         const config = {
             schema,
@@ -675,7 +688,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
         if (!data) {
             return;
         }
-        GoogleApiClientUtils.Docs.Write({
+        GoogleApiClientUtils.Docs.write({
             reference: {
                 title: StrCast(dataDoc.title),
                 handler: id => dataDoc[googleDocKey] = id
diff --git a/src/new_fields/RichTextField.ts b/src/new_fields/RichTextField.ts
index 3e8803a34..4f782816c 100644
--- a/src/new_fields/RichTextField.ts
+++ b/src/new_fields/RichTextField.ts
@@ -9,7 +9,7 @@ import { scriptingGlobal } from "../client/util/Scripting";
 export class RichTextField extends ObjectField {
     @serializable(true)
     readonly Data: string;
-    private Extractor = /,\"text\":\"([^\"\}]*)\"\}/g;
+    private Extractor = /,\"text\":\"([^\}]*)\"\}/g;
 
     constructor(data: string) {
         super();
@@ -33,6 +33,6 @@ export class RichTextField extends ObjectField {
             considering = considering.substring(matches.index + matches[0].length);
             this.Extractor.lastIndex = 0;
         }
-        return contents;
+        return contents.ReplaceAll("\\", "");
     }
 }
\ No newline at end of file
diff --git a/src/server/index.ts b/src/server/index.ts
index abaa29658..ef1829f30 100644
--- a/src/server/index.ts
+++ b/src/server/index.ts
@@ -43,6 +43,8 @@ import * as YoutubeApi from "./apis/youtube/youtubeApiSample";
 import { Response } from 'express-serve-static-core';
 import { GoogleApiServerUtils } from "./apis/google/GoogleApiServerUtils";
 import { GaxiosResponse } from 'gaxios';
+import { Opt } from '../new_fields/Doc';
+import { docs_v1 } from 'googleapis';
 const MongoStore = require('connect-mongo')(session);
 const mongoose = require('mongoose');
 const probe = require("probe-image-size");
@@ -797,23 +799,28 @@ function HandleYoutubeQuery([query, callback]: [YoutubeQueryInput, (result?: any
 const credentials = path.join(__dirname, "./credentials/google_docs_credentials.json");
 const token = path.join(__dirname, "./credentials/google_docs_token.json");
 
+type ApiResponse = Promise<GaxiosResponse>;
+type ApiHandler = (endpoint: docs_v1.Resource$Documents, parameters: any) => ApiResponse;
+type Action = "create" | "retrieve" | "update";
+
+const EndpointHandlerMap = new Map<Action, ApiHandler>([
+    ["create", (api, params) => api.create(params)],
+    ["retrieve", (api, params) => api.get(params)],
+    ["update", (api, params) => api.batchUpdate(params)],
+]);
+
 app.post(RouteStore.googleDocs + ":action", (req, res) => {
     GoogleApiServerUtils.Docs.GetEndpoint({ credentials, token }).then(endpoint => {
-        let results: Promise<GaxiosResponse> | undefined;
-        let documents = endpoint.documents;
-        let parameters = req.body;
-        switch (req.params.action) {
-            case "create":
-                results = documents.create(parameters);
-                break;
-            case "retrieve":
-                results = documents.get(parameters);
-                break;
-            case "update":
-                results = documents.batchUpdate(parameters);
-                break;
+        let handler = EndpointHandlerMap.get(req.params.action);
+        if (handler) {
+            let execute = handler(endpoint.documents, req.body).then(
+                response => res.send(response.data),
+                rejection => res.send(rejection)
+            );
+            execute.catch(exception => res.send(exception));
+            return;
         }
-        !results ? res.send(undefined) : results.then(response => res.send(response.data));
+        res.send(undefined);
     });
 });
 
-- 
cgit v1.2.3-70-g09d2


From 9ea032b9ab14ba17511b1014044dba0236e93837 Mon Sep 17 00:00:00 2001
From: Sam Wilkins <samwilkins333@gmail.com>
Date: Wed, 14 Aug 2019 10:48:23 -0400
Subject: refactored plain text parsing and setting

---
 src/client/views/nodes/FormattedTextBox.tsx | 13 +++++---
 src/new_fields/RichTextField.ts             | 50 ++++++++++++++++++++++-------
 2 files changed, 48 insertions(+), 15 deletions(-)

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

diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 46aed9b2d..5ba2aa0cf 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -12,7 +12,7 @@ import { EditorView } from "prosemirror-view";
 import { Doc, Opt, DocListCast } from "../../../new_fields/Doc";
 import { Id, Copy } from '../../../new_fields/FieldSymbols';
 import { List } from '../../../new_fields/List';
-import { RichTextField } from "../../../new_fields/RichTextField";
+import { RichTextField, ToPlainText, FromPlainText } from "../../../new_fields/RichTextField";
 import { createSchema, listSpec, makeInterface } from "../../../new_fields/Schema";
 import { BoolCast, Cast, NumCast, StrCast, DateCast } from "../../../new_fields/Types";
 import { DocServer } from "../../DocServer";
@@ -296,8 +296,13 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
         let dataDoc = Doc.GetProto(this.props.Document);
         let documentId = StrCast(dataDoc[googleDocKey]);
         if (documentId) {
-            let contents = await GoogleApiClientUtils.Docs.read({ documentId });
-            contents ? console.log(contents) : delete dataDoc[googleDocKey];
+            let exportState = await GoogleApiClientUtils.Docs.read({ documentId });
+            if (exportState) {
+                let data = Cast(dataDoc.data, RichTextField);
+                data && data[FromPlainText](exportState);
+            } else {
+                delete dataDoc[googleDocKey];
+            }
         }
     }
 
@@ -693,7 +698,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
                 title: StrCast(dataDoc.title),
                 handler: id => dataDoc[googleDocKey] = id
             },
-            content: data.plainText()
+            content: data[ToPlainText]()
         });
     }
 
diff --git a/src/new_fields/RichTextField.ts b/src/new_fields/RichTextField.ts
index 4f782816c..9d8a1cecb 100644
--- a/src/new_fields/RichTextField.ts
+++ b/src/new_fields/RichTextField.ts
@@ -4,12 +4,14 @@ import { Deserializable } from "../client/util/SerializationHelper";
 import { Copy, ToScriptString } from "./FieldSymbols";
 import { scriptingGlobal } from "../client/util/Scripting";
 
+export const ToPlainText = Symbol("PlainText");
+export const FromPlainText = Symbol("PlainText");
+
 @scriptingGlobal
 @Deserializable("RichTextField")
 export class RichTextField extends ObjectField {
     @serializable(true)
-    readonly Data: string;
-    private Extractor = /,\"text\":\"([^\}]*)\"\}/g;
+    Data: string;
 
     constructor(data: string) {
         super();
@@ -24,15 +26,41 @@ export class RichTextField extends ObjectField {
         return `new RichTextField("${this.Data}")`;
     }
 
-    plainText = () => {
-        let contents = "";
-        let matches: RegExpExecArray | null;
-        let considering = this.Data;
-        while ((matches = this.Extractor.exec(considering)) !== null) {
-            contents += matches[1];
-            considering = considering.substring(matches.index + matches[0].length);
-            this.Extractor.lastIndex = 0;
+    [ToPlainText]() {
+        let content = JSON.parse(this.Data).doc.content;
+        let paragraphs = content.filter((item: any) => item.type === "paragraph");
+        let output = "";
+        for (let i = 0; i < paragraphs.length; i++) {
+            let paragraph = paragraphs[i];
+            if (paragraph.content) {
+                output += paragraph.content.map((block: any) => block.text).join("");
+            } else {
+                output += i > 0 && paragraphs[i - 1].content ? "\n\n" : "\n";
+            }
         }
-        return contents.ReplaceAll("\\", "");
+        return output;
+    }
+
+    [FromPlainText](plainText: string) {
+        let elements = plainText.split("\n");
+        let parsed = JSON.parse(this.Data);
+        parsed.doc.content = elements.map(text => {
+            let paragraph: any = { type: "paragraph" };
+            if (text.length) {
+                paragraph.content = [{
+                    type: "text",
+                    marks: [],
+                    text
+                }];
+            }
+            return paragraph;
+        });
+        parsed.selection = {
+            type: "text",
+            anchor: 0,
+            head: 0
+        };
+        this.Data = JSON.stringify(parsed);
     }
+
 }
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2


From 13d2be7f66c01ee9f09cb65f567eb3da760df670 Mon Sep 17 00:00:00 2001
From: Sam Wilkins <samwilkins333@gmail.com>
Date: Wed, 14 Aug 2019 15:18:13 -0400
Subject: semi-synchronous editing between dash notes and google docs

---
 package.json                                       |  2 +
 .../apis/google_docs/GoogleApiClientUtils.ts       | 40 ++++++++++++++------
 src/client/views/nodes/FormattedTextBox.tsx        | 44 ++++++++++++++--------
 src/new_fields/RichTextField.ts                    | 25 +++++++-----
 4 files changed, 76 insertions(+), 35 deletions(-)

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

diff --git a/package.json b/package.json
index 326468ab9..7a629d813 100644
--- a/package.json
+++ b/package.json
@@ -63,6 +63,7 @@
         "@types/cookie-parser": "^1.4.1",
         "@types/cookie-session": "^2.0.36",
         "@types/d3-format": "^1.3.1",
+        "@types/diff": "^4.0.2",
         "@types/dotenv": "^6.1.1",
         "@types/express": "^4.16.1",
         "@types/express-flash": "0.0.0",
@@ -127,6 +128,7 @@
         "cookie-session": "^2.0.0-beta.3",
         "crypto-browserify": "^3.11.0",
         "d3-format": "^1.3.2",
+        "diff": "^4.0.1",
         "dotenv": "^8.0.0",
         "express": "^4.16.4",
         "express-flash": "0.0.2",
diff --git a/src/client/apis/google_docs/GoogleApiClientUtils.ts b/src/client/apis/google_docs/GoogleApiClientUtils.ts
index c6c7d7bd4..c1cbba31f 100644
--- a/src/client/apis/google_docs/GoogleApiClientUtils.ts
+++ b/src/client/apis/google_docs/GoogleApiClientUtils.ts
@@ -14,6 +14,11 @@ export namespace GoogleApiClientUtils {
             Update = "update"
         }
 
+        export enum WriteMode {
+            Insert,
+            Replace
+        }
+
         export type DocumentId = string;
         export type Reference = DocumentId | CreateOptions;
         export type TextContent = string | string[];
@@ -37,6 +42,7 @@ export namespace GoogleApiClientUtils {
         export type ReadOptions = RetrieveOptions & { removeNewlines?: boolean };
 
         export interface WriteOptions {
+            mode: WriteMode;
             content: TextContent;
             reference: Reference;
             index?: number; // if excluded, will compute the last index of the document and append the content there
@@ -158,28 +164,40 @@ export namespace GoogleApiClientUtils {
         };
 
         export const write = async (options: WriteOptions): Promise<UpdateResult> => {
+            const requests: docs_v1.Schema$Request[] = [];
             const documentId = await Utils.initialize(options.reference);
             if (!documentId) {
                 return undefined;
             }
             let index = options.index;
-            if (!index) {
+            const mode = options.mode;
+            if (!(index && mode === WriteMode.Insert)) {
                 let schema = await retrieve({ documentId });
                 if (!schema || !(index = Utils.endOf(schema))) {
                     return undefined;
                 }
             }
-            const text = options.content;
-            const updateOptions = {
-                documentId,
-                requests: [{
-                    insertText: {
-                        text: isArray(text) ? text.join("\n") : text,
-                        location: { index }
+            if (mode === WriteMode.Replace) {
+                requests.push({
+                    deleteContentRange: {
+                        range: {
+                            startIndex: 1,
+                            endIndex: index
+                        }
                     }
-                }]
-            };
-            return update(updateOptions);
+                });
+                index = 1;
+            }
+            const text = options.content;
+            requests.push({
+                insertText: {
+                    text: isArray(text) ? text.join("\n") : text,
+                    location: { index }
+                }
+            });
+            let replies = await update({ documentId, requests });
+            console.log(replies);
+            return replies;
         };
 
     }
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 5ba2aa0cf..ad29ce775 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -12,7 +12,7 @@ import { EditorView } from "prosemirror-view";
 import { Doc, Opt, DocListCast } from "../../../new_fields/Doc";
 import { Id, Copy } from '../../../new_fields/FieldSymbols';
 import { List } from '../../../new_fields/List';
-import { RichTextField, ToPlainText, FromPlainText } from "../../../new_fields/RichTextField";
+import { RichTextField, ToGoogleDocText, FromGoogleDocText } from "../../../new_fields/RichTextField";
 import { createSchema, listSpec, makeInterface } from "../../../new_fields/Schema";
 import { BoolCast, Cast, NumCast, StrCast, DateCast } from "../../../new_fields/Types";
 import { DocServer } from "../../DocServer";
@@ -39,6 +39,7 @@ import { DateField } from '../../../new_fields/DateField';
 import { Utils } from '../../../Utils';
 import { MainOverlayTextBox } from '../MainOverlayTextBox';
 import { GoogleApiClientUtils } from '../../apis/google_docs/GoogleApiClientUtils';
+import * as diff from "diff";
 
 library.add(faEdit);
 library.add(faSmile, faTextHeight, faUpload);
@@ -299,7 +300,9 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
             let exportState = await GoogleApiClientUtils.Docs.read({ documentId });
             if (exportState) {
                 let data = Cast(dataDoc.data, RichTextField);
-                data && data[FromPlainText](exportState);
+                if (data) {
+                    dataDoc.data = new RichTextField(data[FromGoogleDocText](exportState));
+                }
             } else {
                 delete dataDoc[googleDocKey];
             }
@@ -629,6 +632,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
             this._undoTyping.end();
             this._undoTyping = undefined;
         }
+        this.updateGoogleDoc();
     }
     public _undoTyping?: UndoManager.Batch;
     onKeyPress = (e: React.KeyboardEvent) => {
@@ -683,23 +687,33 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
         });
         ContextMenu.Instance.addItem({ description: "Text Funcs...", subitems: subitems, icon: "text-height" });
         if (!(googleDocKey in Doc.GetProto(this.props.Document))) {
-            ContextMenu.Instance.addItem({ description: "Export to Google Doc...", event: this.exportToGoogleDoc, icon: "upload" });
+            ContextMenu.Instance.addItem({
+                description: "Export to Google Doc...",
+                event: this.updateGoogleDoc,
+                icon: "upload"
+            });
         }
     }
 
-    exportToGoogleDoc = () => {
-        const dataDoc = Doc.GetProto(this.props.Document);
-        const data = Cast(dataDoc.data, RichTextField);
-        if (!data) {
-            return;
+    updateGoogleDoc = () => {
+        let modes = GoogleApiClientUtils.Docs.WriteMode;
+        let mode = modes.Replace;
+        let reference: Opt<GoogleApiClientUtils.Docs.Reference> = Cast(this.dataDoc[googleDocKey], "string");
+        if (!reference) {
+            mode = modes.Insert;
+            reference = {
+                title: StrCast(this.dataDoc.title),
+                handler: id => this.dataDoc[googleDocKey] = id
+            };
+        }
+        const data = Cast(this.dataDoc.data, RichTextField);
+        if (data) {
+            GoogleApiClientUtils.Docs.write({
+                mode,
+                content: data[ToGoogleDocText](),
+                reference
+            });
         }
-        GoogleApiClientUtils.Docs.write({
-            reference: {
-                title: StrCast(dataDoc.title),
-                handler: id => dataDoc[googleDocKey] = id
-            },
-            content: data[ToPlainText]()
-        });
     }
 
     render() {
diff --git a/src/new_fields/RichTextField.ts b/src/new_fields/RichTextField.ts
index f0284b1b8..92b19b921 100644
--- a/src/new_fields/RichTextField.ts
+++ b/src/new_fields/RichTextField.ts
@@ -4,14 +4,14 @@ import { Deserializable } from "../client/util/SerializationHelper";
 import { Copy, ToScriptString } from "./FieldSymbols";
 import { scriptingGlobal } from "../client/util/Scripting";
 
-export const ToPlainText = Symbol("PlainText");
-export const FromPlainText = Symbol("PlainText");
+export const ToGoogleDocText = Symbol("PlainText");
+export const FromGoogleDocText = Symbol("PlainText");
 
 @scriptingGlobal
 @Deserializable("RichTextField")
 export class RichTextField extends ObjectField {
     @serializable(true)
-    Data: string;
+    readonly Data: string;
 
     constructor(data: string) {
         super();
@@ -26,24 +26,28 @@ export class RichTextField extends ObjectField {
         return `new RichTextField("${this.Data}")`;
     }
 
-    [ToPlainText]() {
+    [ToGoogleDocText]() {
         let content = JSON.parse(this.Data).doc.content;
         let paragraphs = content.filter((item: any) => item.type === "paragraph");
         let output = "";
         for (let i = 0; i < paragraphs.length; i++) {
             let paragraph = paragraphs[i];
+            let addNewLine = i > 0 ? paragraphs[i - 1].content : false;
             if (paragraph.content) {
                 output += paragraph.content.map((block: any) => block.text).join("");
             } else {
-                output += i > 0 && paragraphs[i - 1].content ? "\n\n" : "\n";
+                output += "\n";
             }
+            addNewLine && (output += "\n");
         }
         return output;
     }
 
-    [FromPlainText](plainText: string) {
+    [FromGoogleDocText](plainText: string) {
         let elements = plainText.split("\n");
+        !elements[elements.length - 1].length && elements.pop();
         let parsed = JSON.parse(this.Data);
+        let blankCount = 0;
         parsed.doc.content = elements.map(text => {
             let paragraph: any = { type: "paragraph" };
             if (text.length) {
@@ -52,15 +56,18 @@ export class RichTextField extends ObjectField {
                     marks: [],
                     text
                 }];
+            } else {
+                blankCount++;
             }
             return paragraph;
         });
+        let selection = plainText.length + 2 * blankCount;
         parsed.selection = {
             type: "text",
-            anchor: plainText.length,
-            head: plainText.length
+            anchor: selection,
+            head: selection
         };
-        this.Data = JSON.stringify(parsed);
+        return JSON.stringify(parsed);
     }
 
 }
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2


From e09f39a711fc109b1c80f4431efd01e6d251ab86 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Wed, 14 Aug 2019 17:57:37 -0400
Subject: fixed text/inking problems.

---
 src/client/views/InkingCanvas.tsx           | 4 ++--
 src/client/views/nodes/DocumentView.tsx     | 2 +-
 src/client/views/nodes/FormattedTextBox.tsx | 2 +-
 3 files changed, 4 insertions(+), 4 deletions(-)

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

diff --git a/src/client/views/InkingCanvas.tsx b/src/client/views/InkingCanvas.tsx
index b08133d80..1cfa8d644 100644
--- a/src/client/views/InkingCanvas.tsx
+++ b/src/client/views/InkingCanvas.tsx
@@ -170,12 +170,12 @@ export class InkingCanvas extends React.Component<InkCanvasProps> {
         return [!penPaths.length ? (null) :
             <svg className={`inkingCanvas-paths-ink`} key="Pens"
                 style={{ left: `${this.inkMidX - this.maxCanvasDim}px`, top: `${this.inkMidY - this.maxCanvasDim}px` }} >
-                {}
+                {penPaths}
             </svg>,
         !markerPaths.length ? (null) :
             <svg className={`inkingCanvas-paths-markers`} key="Markers"
                 style={{ left: `${this.inkMidX - this.maxCanvasDim}px`, top: `${this.inkMidY - this.maxCanvasDim}px` }}>
-                {}
+                {markerPaths}
             </svg>];
     }
 
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 8af56a1d4..188a306ec 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -378,6 +378,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         }
     }
     onPointerDown = (e: React.PointerEvent): void => {
+        if (e.nativeEvent.cancelBubble) return;
         this._downX = e.clientX;
         this._downY = e.clientY;
         this._hitExpander = DocListCast(this.props.Document.subBulletDocs).length > 0;
@@ -728,7 +729,6 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
 
 
     render() {
-        trace();
         let backgroundColor = this.layoutDoc.isBackground || (this.props.ContainingCollectionView && this.props.ContainingCollectionView.props.Document.clusterOverridesDefaultBackground && this.layoutDoc.backgroundColor === this.layoutDoc.defaultBackgroundColor) ?
             this.props.backgroundColor(this.layoutDoc) || StrCast(this.layoutDoc.backgroundColor) :
             StrCast(this.layoutDoc.backgroundColor) || this.props.backgroundColor(this.layoutDoc);
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 732576328..6842c782b 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -475,7 +475,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
     }
 
     onPointerDown = (e: React.PointerEvent): void => {
-        if (this.onClick && e.button === 0) {
+        if (this.props.onClick && e.button === 0) {
             e.preventDefault();
         }
         if (e.button === 0 && this.props.isSelected() && !e.altKey && !e.ctrlKey && !e.metaKey) {
-- 
cgit v1.2.3-70-g09d2


From 71f27b718d9be29034ba233b5be18ea29f59f30b Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Wed, 14 Aug 2019 20:40:53 -0400
Subject: fixed text menu and text selection

---
 src/client/util/TooltipTextMenu.tsx         | 9 ++++++++-
 src/client/views/MainOverlayTextBox.tsx     | 2 +-
 src/client/views/nodes/FormattedTextBox.tsx | 8 ++++++++
 3 files changed, 17 insertions(+), 2 deletions(-)

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

diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx
index 48f02d38a..783492d74 100644
--- a/src/client/util/TooltipTextMenu.tsx
+++ b/src/client/util/TooltipTextMenu.tsx
@@ -67,6 +67,8 @@ export class TooltipTextMenu {
     @observable
     private _storedMarks: Mark<any>[] | null | undefined;
 
+    public HackToFixTextSelectionGlitch: boolean = false;
+
 
     constructor(view: EditorView, editorProps: FieldViewProps & FormattedTextBoxProps) {
         this.view = view;
@@ -190,6 +192,10 @@ export class TooltipTextMenu {
         this.updateListItemDropdown(":", this.listTypeBtnDom);
 
         this.update(view, undefined);
+
+        // add tooltip to outerdiv to circumvent scaling problem
+        const outer_div = this.editorProps.outer_div;
+        outer_div && outer_div(this.wrapper);
     }
 
     //label of dropdown will change to given label
@@ -849,7 +855,8 @@ export class TooltipTextMenu {
                 this.updateFontSizeDropdown("Various");
             }
         }
-        this.view.dispatch(this.view.state.tr.setStoredMarks(this._activeMarks));
+        !this.HackToFixTextSelectionGlitch &&
+            this.view.dispatch(this.view.state.tr.setStoredMarks(this._activeMarks)); // bcz: what's the purpose of this line?  It messes up text selection without the Hack.
 
         this.update_mark_doms();
     }
diff --git a/src/client/views/MainOverlayTextBox.tsx b/src/client/views/MainOverlayTextBox.tsx
index 2865fe2b6..196e5414d 100644
--- a/src/client/views/MainOverlayTextBox.tsx
+++ b/src/client/views/MainOverlayTextBox.tsx
@@ -145,7 +145,7 @@ export class MainOverlayTextBox extends React.Component<MainOverlayTextBoxProps>
                                 onClick={undefined}
                                 isSelected={returnTrue} select={emptyFunction} renderDepth={0} selectOnLoad={true}
                                 ContainingCollectionView={undefined} whenActiveChanged={emptyFunction} active={returnTrue} ContentScaling={returnOne}
-                                ScreenToLocalTransform={this._textXf} PanelWidth={returnZero} PanelHeight={returnZero} focus={emptyFunction} addDocTab={this.addDocTab} />
+                                ScreenToLocalTransform={this._textXf} PanelWidth={returnZero} PanelHeight={returnZero} focus={emptyFunction} addDocTab={this.addDocTab} outer_div={(tooltip: HTMLElement) => { this._tooltip = tooltip; this.updateTooltip(); }} />
                         </div>
                     </div>
                 </div>
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 6842c782b..800bbdbf9 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -48,6 +48,7 @@ export interface FormattedTextBoxProps {
     hideOnLeave?: boolean;
     height?: string;
     color?: string;
+    outer_div?: (domminus: HTMLElement) => void;
     firstinstance?: boolean;
 }
 
@@ -69,6 +70,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
     private _editorView: Opt<EditorView>;
     private static _toolTipTextMenu: TooltipTextMenu | undefined = undefined;
     private _applyingChange: boolean = false;
+    private _outerdiv?: (dominus: HTMLElement) => void;
     private _linkClicked = "";
     private _reactionDisposer: Opt<IReactionDisposer>;
     private _searchReactionDisposer?: Lambda;
@@ -126,6 +128,10 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
             DragManager.StartDragFunctions.push(() => FormattedTextBox.InputBoxOverlay = undefined);
         }
 
+        if (this.props.outer_div) {
+            this._outerdiv = this.props.outer_div;
+        }
+
         document.addEventListener("paste", this.paste);
     }
 
@@ -163,7 +169,9 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
     dispatchTransaction = (tx: Transaction) => {
         if (this._editorView) {
             const state = this._editorView.state.apply(tx);
+            FormattedTextBox._toolTipTextMenu && (FormattedTextBox._toolTipTextMenu.HackToFixTextSelectionGlitch = true);
             this._editorView.updateState(state);
+            FormattedTextBox._toolTipTextMenu && (FormattedTextBox._toolTipTextMenu.HackToFixTextSelectionGlitch = false);
             if (state.selection.empty && FormattedTextBox._toolTipTextMenu) {
                 const marks = tx.storedMarks;
                 if (marks) { FormattedTextBox._toolTipTextMenu.mark_key_pressed(marks); }
-- 
cgit v1.2.3-70-g09d2


From 5a2f6ca6f8f914e0c355c2211f506fc701451e91 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Wed, 14 Aug 2019 23:19:23 -0400
Subject: fixed autoHeight resizing for textboxes.

---
 src/client/views/DocumentDecorations.tsx    |  2 +-
 src/client/views/MainOverlayTextBox.tsx     |  3 +-
 src/client/views/nodes/FormattedTextBox.tsx | 66 ++++++++++-------------------
 3 files changed, 25 insertions(+), 46 deletions(-)

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

diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index d537e2dac..df526e01c 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -523,7 +523,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
                 break;
         }
 
-        runInAction(() => FormattedTextBox.InputBoxOverlay = undefined);
+        if (!this._resizing) runInAction(() => FormattedTextBox.InputBoxOverlay = undefined);
         SelectionManager.SelectedDocuments().forEach(element => {
             if (dX !== 0 || dY !== 0 || dW !== 0 || dH !== 0) {
                 let doc = PositionDocument(element.props.Document);
diff --git a/src/client/views/MainOverlayTextBox.tsx b/src/client/views/MainOverlayTextBox.tsx
index 196e5414d..b14a1e0ea 100644
--- a/src/client/views/MainOverlayTextBox.tsx
+++ b/src/client/views/MainOverlayTextBox.tsx
@@ -130,12 +130,13 @@ export class MainOverlayTextBox extends React.Component<MainOverlayTextBoxProps>
     render() {
         this.TextDoc; this.TextDataDoc;
         if (FormattedTextBox.InputBoxOverlay && this._textTargetDiv) {
+            let wid = FormattedTextBox.InputBoxOverlay.props.Document.width; // need to force overlay to render when underlying text box is resized (eg, w/ DocDecorations)
             let textRect = this._textTargetDiv.getBoundingClientRect();
             let s = this._textXf().Scale;
             let location = this._textBottom ? textRect.bottom : textRect.top;
             let hgt = this._textAutoHeight || this._textBottom ? "auto" : this._textTargetDiv.clientHeight;
             return <div ref={this._setouterdiv} className="mainOverlayTextBox-unscaled_div" style={{ transform: `translate(${textRect.left}px, ${location}px)` }} >
-                <div className="mainOverlayTextBox-textInput" style={{ transform: `scale(${1 / s},${1 / s})`, width: "auto", height: "0px" }} >
+                <div className="mainOverlayTextBox-textInput" style={{ transform: `scale(${1 / s})`, width: "auto", height: "0px" }} >
                     <div className="mainOverlayTextBox-textInput" onPointerDown={this.textBoxDown} ref={this._textProxyDiv} onScroll={this.textScroll}
                         style={{ width: `${textRect.width * s}px`, height: "0px" }}>
                         <div style={{ height: hgt, width: "100%", position: "absolute", bottom: this._textBottom ? "0px" : undefined }}>
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 800bbdbf9..516e36d5b 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -1,20 +1,21 @@
 import { library } from '@fortawesome/fontawesome-svg-core';
 import { faEdit, faSmile, faTextHeight } from '@fortawesome/free-solid-svg-icons';
-import { action, IReactionDisposer, observable, reaction, runInAction, computed, Lambda, trace } from "mobx";
+import { action, computed, IReactionDisposer, Lambda, observable, reaction } from "mobx";
 import { observer } from "mobx-react";
 import { baseKeymap } from "prosemirror-commands";
 import { history } from "prosemirror-history";
 import { keymap } from "prosemirror-keymap";
-import { Node as ProsNode } from "prosemirror-model";
-import { EditorState, Plugin, Transaction, Selection } from "prosemirror-state";
-import { NodeType, Slice, Node, Fragment } from 'prosemirror-model';
+import { Fragment, Node, Node as ProsNode, NodeType, Slice } from "prosemirror-model";
+import { EditorState, Plugin, Transaction } from "prosemirror-state";
 import { EditorView } from "prosemirror-view";
-import { Doc, Opt, DocListCast } from "../../../new_fields/Doc";
-import { Id, Copy } from '../../../new_fields/FieldSymbols';
+import { DateField } from '../../../new_fields/DateField';
+import { Doc, DocListCast, Opt, WidthSym } from "../../../new_fields/Doc";
+import { Copy, Id } from '../../../new_fields/FieldSymbols';
 import { List } from '../../../new_fields/List';
 import { RichTextField } from "../../../new_fields/RichTextField";
-import { createSchema, listSpec, makeInterface } from "../../../new_fields/Schema";
-import { BoolCast, Cast, NumCast, StrCast, DateCast } from "../../../new_fields/Types";
+import { createSchema, makeInterface } from "../../../new_fields/Schema";
+import { BoolCast, Cast, DateCast, NumCast, StrCast } from "../../../new_fields/Types";
+import { Utils } from '../../../Utils';
 import { DocServer } from "../../DocServer";
 import { Docs, DocUtils } from '../../documents/Documents';
 import { DocumentManager } from '../../util/DocumentManager';
@@ -26,16 +27,12 @@ import { SelectionManager } from "../../util/SelectionManager";
 import { TooltipLinkingMenu } from "../../util/TooltipLinkingMenu";
 import { TooltipTextMenu } from "../../util/TooltipTextMenu";
 import { undoBatch, UndoManager } from "../../util/UndoManager";
-import { ContextMenu } from "../../views/ContextMenu";
-import { ContextMenuProps } from '../ContextMenuItem';
 import { DocComponent } from "../DocComponent";
 import { InkingControl } from "../InkingControl";
+import { MainOverlayTextBox } from '../MainOverlayTextBox';
 import { FieldView, FieldViewProps } from "./FieldView";
 import "./FormattedTextBox.scss";
 import React = require("react");
-import { DateField } from '../../../new_fields/DateField';
-import { Utils } from '../../../Utils';
-import { MainOverlayTextBox } from '../MainOverlayTextBox';
 
 library.add(faEdit);
 library.add(faSmile, faTextHeight);
@@ -70,11 +67,11 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
     private _editorView: Opt<EditorView>;
     private static _toolTipTextMenu: TooltipTextMenu | undefined = undefined;
     private _applyingChange: boolean = false;
-    private _outerdiv?: (dominus: HTMLElement) => void;
     private _linkClicked = "";
     private _reactionDisposer: Opt<IReactionDisposer>;
     private _searchReactionDisposer?: Lambda;
     private _textReactionDisposer: Opt<IReactionDisposer>;
+    private _heightReactionDisposer: Opt<IReactionDisposer>;
     private _proxyReactionDisposer: Opt<IReactionDisposer>;
     private dropDisposer?: DragManager.DragDropDisposer;
     public get CurrentDiv(): HTMLDivElement { return this._ref.current!; }
@@ -128,10 +125,6 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
             DragManager.StartDragFunctions.push(() => FormattedTextBox.InputBoxOverlay = undefined);
         }
 
-        if (this.props.outer_div) {
-            this._outerdiv = this.props.outer_div;
-        }
-
         document.addEventListener("paste", this.paste);
     }
 
@@ -257,25 +250,6 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
                 this.props.Document.layout = de.data.draggedDocuments[0];
                 de.data.draggedDocuments[0].isTemplate = true;
                 e.stopPropagation();
-                // let ldocs = Cast(this.dataDoc.subBulletDocs, listSpec(Doc));
-                // if (!ldocs) {
-                //     this.dataDoc.subBulletDocs = new List<Doc>([]);
-                // }
-                // ldocs = Cast(this.dataDoc.subBulletDocs, listSpec(Doc));
-                // if (!ldocs) return;
-                // if (!ldocs || !ldocs[0] || ldocs[0] instanceof Promise || StrCast((ldocs[0] as Doc).layout).indexOf("CollectionView") === -1) {
-                //     ldocs.splice(0, 0, Docs.StackingDocument([], { title: StrCast(this.dataDoc.title) + "-subBullets", x: NumCast(this.props.Document.x), y: NumCast(this.props.Document.y) + NumCast(this.props.Document.height), width: 300, height: 300 }));
-                //     this.props.addDocument && this.props.addDocument(ldocs[0] as Doc);
-                //     this.props.Document.templates = new List<string>([Templates.Bullet.Layout]);
-                //     this.props.Document.isBullet = true;
-                // }
-                // let stackDoc = (ldocs[0] as Doc);
-                // if (de.data.moveDocument) {
-                //     de.data.moveDocument(de.data.draggedDocuments[0], stackDoc, (doc) => {
-                //         Cast(stackDoc.data, listSpec(Doc))!.push(doc);
-                //         return true;
-                //     });
-                // }
             }
         }
     }
@@ -317,12 +291,15 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
                 const field = this.dataDoc ? Cast(this.dataDoc[this.props.fieldKey], RichTextField) : undefined;
                 return field ? field.Data : `{"doc":{"type":"doc","content":[]},"selection":{"type":"text","anchor":0,"head":0}}`;
             },
-            field2 => {
-                this._editorView && !this._applyingChange &&
-                    this._editorView.updateState(EditorState.fromJSON(config, JSON.parse(field2)));
-            }
+            field2 => this._editorView && !this._applyingChange &&
+                this._editorView.updateState(EditorState.fromJSON(config, JSON.parse(field2)))
         );
 
+        this.props.isOverlay && (this._heightReactionDisposer = reaction(
+            () => this.props.Document[WidthSym](),
+            () => this.tryUpdateHeight()
+        ));
+
         this._textReactionDisposer = reaction(
             () => this.extensionDoc,
             () => {
@@ -479,6 +456,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
         this._reactionDisposer && this._reactionDisposer();
         this._proxyReactionDisposer && this._proxyReactionDisposer();
         this._textReactionDisposer && this._textReactionDisposer();
+        this._heightReactionDisposer && this._heightReactionDisposer();
         this._searchReactionDisposer && this._searchReactionDisposer();
     }
 
@@ -631,8 +609,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
 
     @action
     tryUpdateHeight() {
-        if (this.props.isOverlay && this.props.Document.autoHeight) {
-            let self = this;
+        if (this.props.Document.autoHeight && this.props.isOverlay) {
             let xf = this._ref.current!.getBoundingClientRect();
             let scrBounds = this.props.ScreenToLocalTransform().transformBounds(0, 0, xf.width, xf.height);
             let nh = this.props.Document.isTemplate ? 0 : NumCast(this.dataDoc.nativeHeight, 0);
@@ -671,8 +648,9 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
         return (
             <div className={`formattedTextBox-cont-${style}`} ref={this._ref}
                 style={{
+                    overflowY: this.props.Document.autoHeight ? "hidden" : "auto",
                     height: this.props.height ? this.props.height : undefined,
-                    background: this.props.hideOnLeave ? "rgba(0,0,0,0.4)" : undefined,
+                    background: this.props.hideOnLeave ? "rgba(0,0,0 ,0.4)" : undefined,
                     opacity: this.props.hideOnLeave ? (this._entered || this.props.isSelected() || Doc.IsBrushed(this.props.Document) ? 1 : 0.1) : 1,
                     color: this.props.color ? this.props.color : this.props.hideOnLeave ? "white" : "inherit",
                     pointerEvents: interactive,
-- 
cgit v1.2.3-70-g09d2


From b9f0c3d05eab364911007beb3c85d6d942097dab Mon Sep 17 00:00:00 2001
From: monikahedman <monika_hedman@brown.edu>
Date: Thu, 15 Aug 2019 16:27:06 -0400
Subject: getting rid of checkbox

---
 src/client/util/RichTextSchema.tsx          | 36 -----------------------------
 src/client/util/TooltipTextMenu.tsx         | 29 -----------------------
 src/client/views/nodes/FormattedTextBox.tsx |  3 +--
 3 files changed, 1 insertion(+), 67 deletions(-)

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

diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx
index 733c50d20..a581b7578 100644
--- a/src/client/util/RichTextSchema.tsx
+++ b/src/client/util/RichTextSchema.tsx
@@ -112,18 +112,6 @@ export const nodes: { [index: string]: NodeSpec } = {
         // }]
     },
 
-    checkbox: {
-        inline: true,
-        attrs: {
-            visibility: { default: false }
-        },
-        group: "inline",
-        toDOM(node) {
-            const attrs = { style: `width: 40px` };
-            return ["span", { ...node.attrs, ...attrs }];
-        },
-    },
-
     // :: NodeSpec An inline image (`<img>`) node. Supports `src`,
     // `alt`, and `href` attributes. The latter two default to the empty
     // string.
@@ -203,19 +191,6 @@ export const nodes: { [index: string]: NodeSpec } = {
         // toDOM() { return ulDOM }
     },
 
-    checkbox_list: {
-        content: 'checklist_item+',
-        marks: '_',
-        group: 'block',
-        // inline: true,
-        parseDOM: [
-            { tag: "ul" }
-        ],
-        toDOM() {
-            return ["ul", { style: 'list-style: none' }, 0];
-        },
-    },
-
     //bullet_list: {
     //  content: 'list_item+',
     // group: 'block',
@@ -229,17 +204,6 @@ export const nodes: { [index: string]: NodeSpec } = {
         content: 'paragraph block*'
     },
 
-    checklist_item: {
-        content: 'paragraph block*',
-        parseDOM: [{ tag: "li" }],
-        // toDOM() {
-        //     return ["li", { style: 'content: checkbox' }, 0];
-        // },
-        toDOM() {
-            return ["li", 0];
-        },
-        defining: true
-    }
 };
 
 const emDOM: DOMOutputSpecArray = ["em", 0];
diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx
index 389d96636..3cc70382c 100644
--- a/src/client/util/TooltipTextMenu.tsx
+++ b/src/client/util/TooltipTextMenu.tsx
@@ -187,7 +187,6 @@ export class TooltipTextMenu {
         this.tooltip.appendChild(this._brushdom);
         this.tooltip.appendChild(this.createLink().render(this.view).dom);
         this.tooltip.appendChild(this.createStar().render(this.view).dom);
-        this.tooltip.appendChild(this.createCheckbox().render(this.view).dom);
 
         this.updateListItemDropdown(":", this.listTypeBtnDom);
 
@@ -435,14 +434,6 @@ export class TooltipTextMenu {
         return true;
     }
 
-    public static insertCheckbox(state: EditorState<any>, dispatch: any) {
-        let newNode = schema.nodes.checkbox.create({ visibility: false });
-        if (dispatch) {
-            dispatch(state.tr.replaceSelectionWith(newNode));
-        }
-        return true;
-    }
-
     //will display a remove-list-type button if selection is in list, otherwise will show list type dropdown
     updateListItemDropdown(label: string, listTypeBtn: any) {
         //remove old btn
@@ -455,7 +446,6 @@ export class TooltipTextMenu {
         });
         //option to remove the list formatting
         toAdd.push(this.dropdownNodeBtn("X", "color: black; width: 40px;", undefined, this.view, this.listTypes, this.changeToNodeType));
-        toAdd.push(this.dropdownNodeBtn("⬜", "color:black; width:40px;", schema.nodes.checkbox_list, this.view, this.listTypes, this.changeToNodeType))
 
         listTypeBtn = (new Dropdown(toAdd, {
             label: label,
@@ -519,11 +509,6 @@ export class TooltipTextMenu {
         liftListItem(schema.nodes.list_item)(view.state, view.dispatch);
         if (nodeType) { //add new
             wrapInList(nodeType)(view.state, view.dispatch);
-            // console.log(nodeType === schema.nodes.checkbox_list)
-            // if (nodeType === schema.nodes.checkbox_list) {
-            //     TooltipTextMenu.insertCheckbox(view.state, view.dispatch)
-            // }
-
         }
     }
 
@@ -558,20 +543,6 @@ export class TooltipTextMenu {
         });
     }
 
-    createCheckbox() {
-        return new MenuItem({
-            title: "Checkbox",
-            label: "Checkbox",
-            icon: icons.code,
-            css: "color:white",
-            class: "checkbox",
-            execEvent: "",
-            run: (state, dispatch) => {
-                TooltipTextMenu.insertCheckbox(state, dispatch);
-            }
-        })
-    }
-
     deleteLinkItem() {
         const icon = {
             height: 16, width: 16,
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index afdc035e8..7ef348e9c 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -21,7 +21,7 @@ import { DocumentManager } from '../../util/DocumentManager';
 import { DragManager } from "../../util/DragManager";
 import buildKeymap from "../../util/ProsemirrorExampleTransfer";
 import { inpRules } from "../../util/RichTextRules";
-import { ImageResizeView, schema, SummarizedView, CheckboxView } from "../../util/RichTextSchema";
+import { ImageResizeView, schema, SummarizedView } from "../../util/RichTextSchema";
 import { SelectionManager } from "../../util/SelectionManager";
 import { TooltipLinkingMenu } from "../../util/TooltipLinkingMenu";
 import { TooltipTextMenu } from "../../util/TooltipTextMenu";
@@ -451,7 +451,6 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
                 nodeViews: {
                     image(node, view, getPos) { return new ImageResizeView(node, view, getPos); },
                     star(node, view, getPos) { return new SummarizedView(node, view, getPos); },
-                    checkbox(node, view, getPos) { return new CheckboxView(node, view, getPos) as NodeView<any>; }
                 },
                 clipboardTextSerializer: this.clipboardTextSerializer,
                 handlePaste: this.handlePaste,
-- 
cgit v1.2.3-70-g09d2


From 6bbf8df1b246647ae478103504e73c98df7b8183 Mon Sep 17 00:00:00 2001
From: monikahedman <monika_hedman@brown.edu>
Date: Thu, 15 Aug 2019 18:07:04 -0400
Subject: text paste working!

---
 src/client/views/PreviewCursor.tsx                 | 31 +++++++++------
 .../collections/collectionFreeForm/MarqueeView.tsx |  3 +-
 src/client/views/nodes/FormattedTextBox.tsx        | 46 +++++++++++-----------
 3 files changed, 46 insertions(+), 34 deletions(-)

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

diff --git a/src/client/views/PreviewCursor.tsx b/src/client/views/PreviewCursor.tsx
index 04ec51218..dbda46dbc 100644
--- a/src/client/views/PreviewCursor.tsx
+++ b/src/client/views/PreviewCursor.tsx
@@ -4,13 +4,15 @@ import "normalize.css";
 import * as React from 'react';
 import "./PreviewCursor.scss";
 import { Docs } from '../documents/Documents';
-import { Transform } from 'prosemirror-transform';
+// import { Transform } from 'prosemirror-transform';
 import { Doc } from '../../new_fields/Doc';
+import { Transform } from "../util/Transform";
 
 @observer
 export class PreviewCursor extends React.Component<{}> {
     private _prompt = React.createRef<HTMLDivElement>();
     static _onKeyPress?: (e: KeyboardEvent) => void;
+    static _getTransform: () => Transform;
     static _addLiveTextDoc: (doc: Doc) => void;
     @observable static _clickPoint = [0, 0];
     @observable public static Visible = false;
@@ -26,22 +28,28 @@ export class PreviewCursor extends React.Component<{}> {
     }
 
     paste = (e: ClipboardEvent) => {
-        console.log("pasting")
         if (PreviewCursor.Visible) {
-            console.log("preview is visible")
             if (e.clipboardData) {
-                //what needs to be done with this?
-                console.log(e.clipboardData.getData("text/html"));
+                //keeping these just to hold onto types of pastes
+                //what needs to be done with html?
+                // console.log(e.clipboardData.getData("text/html"));
                 // console.log(e.clipboardData.getData("text/csv"));
-                console.log(e.clipboardData.getData("text/plain"));
-                console.log(e.clipboardData.getData("image/png"));
-                console.log(e.clipboardData.getData("image/jpg"));
-                console.log(e.clipboardData.getData("image/jpeg"));
+                // console.log(e.clipboardData.getData("text/plain"));
+                // console.log(e.clipboardData.getData("image/png"));
+                // console.log(e.clipboardData.getData("image/jpg"));
+                // console.log(e.clipboardData.getData("image/jpeg"));
 
                 // pasting in text
                 if (e.clipboardData.getData("text/plain") !== "") {
                     let text = e.clipboardData.getData("text/plain");
-                    let newBox = Docs.Create.TextDocument({ width: 200, height: 100, x: PreviewCursor._clickPoint[0], y: PreviewCursor._clickPoint[1], title: "-typed text-" });
+                    let newPoint = PreviewCursor._getTransform().transformPoint(PreviewCursor._clickPoint[0], PreviewCursor._clickPoint[1]);
+                    let newBox = Docs.Create.TextDocument({
+                        width: 200, height: 100,
+                        x: newPoint[0],
+                        y: newPoint[1],
+                        title: "-typed text-"
+                    });
+
                     newBox.proto!.autoHeight = true;
                     PreviewCursor._addLiveTextDoc(newBox);
                 }
@@ -69,10 +77,11 @@ export class PreviewCursor extends React.Component<{}> {
         }
     }
     @action
-    public static Show(x: number, y: number, onKeyPress: (e: KeyboardEvent) => void, addLiveText: (doc: Doc) => void) {
+    public static Show(x: number, y: number, onKeyPress: (e: KeyboardEvent) => void, addLiveText: (doc: Doc) => void, getTransform: () => Transform) {
         this._clickPoint = [x, y];
         this._onKeyPress = onKeyPress;
         this._addLiveTextDoc = addLiveText;
+        this._getTransform = getTransform;
         setTimeout(action(() => this.Visible = true), (1));
     }
     render() {
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 08d2a8adf..72444983c 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -203,7 +203,8 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
     onClick = (e: React.MouseEvent): void => {
         if (Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD &&
             Math.abs(e.clientY - this._downY) < Utils.DRAG_THRESHOLD) {
-            PreviewCursor.Show(e.clientX, e.clientY, this.onKeyPress, this.props.addLiveTextDocument);
+            //this is probably the wrong transform
+            PreviewCursor.Show(e.clientX, e.clientY, this.onKeyPress, this.props.addLiveTextDocument, this.props.getTransform);
             // let the DocumentView stopPropagation of this event when it selects this document
         } else {  // why do we get a click event when the cursor have moved a big distance?
             // let's cut it off here so no one else has to deal with it.
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index a304cb297..25f611f19 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -134,28 +134,31 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
 
 
     paste = (e: ClipboardEvent) => {
+        //this is throwing a ton of erros so i had to comment it out
         if (e.clipboardData && this._editorView) {
-            let pdfPasteText = `${Utils.GenerateDeterministicGuid("pdf paste")}`;
-            for (let i = 0; i < e.clipboardData.items.length; i++) {
-                let item = e.clipboardData.items.item(i);
-                if (item.type === "text/plain") {
-                    item.getAsString((text) => {
-                        let pdfPasteIndex = text.indexOf(pdfPasteText);
-                        if (pdfPasteIndex > -1) {
-                            let insertText = text.substr(0, pdfPasteIndex);
-                            const tx = this._editorView!.state.tr.insertText(insertText);
-                            // tx.setSelection(new Selection(tx.))
-                            const state = this._editorView!.state;
-                            this._editorView!.dispatch(tx);
-                            if (FormattedTextBox._toolTipTextMenu) {
-                                // this._toolTipTextMenu.makeLinkWithState(state)
-                            }
-                            e.stopPropagation();
-                            e.preventDefault();
-                        }
-                    });
-                }
-            }
+            // let pdfPasteText = `${Utils.GenerateDeterministicGuid("pdf paste")}`;
+            // for (let i = 0; i < e.clipboardData.items.length; i++) {
+            //     let item = e.clipboardData.items.item(i);
+            //     console.log(item)
+            //     if (item.type === "text/plain") {
+            //         console.log("plain")
+            //         item.getAsString((text) => {
+            //             let pdfPasteIndex = text.indexOf(pdfPasteText);
+            //             if (pdfPasteIndex > -1) {
+            //                 let insertText = text.substr(0, pdfPasteIndex);
+            //                 const tx = this._editorView!.state.tr.insertText(insertText);
+            //                 // tx.setSelection(new Selection(tx.))
+            //                 const state = this._editorView!.state;
+            //                 this._editorView!.dispatch(tx);
+            //                 if (FormattedTextBox._toolTipTextMenu) {
+            //                     // this._toolTipTextMenu.makeLinkWithState(state)
+            //                 }
+            //                 e.stopPropagation();
+            //                 e.preventDefault();
+            //             }
+            //         });
+            //     }
+            // }
         }
     }
 
@@ -167,7 +170,6 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
             FormattedTextBox._toolTipTextMenu && (FormattedTextBox._toolTipTextMenu.HackToFixTextSelectionGlitch = false);
             if (state.selection.empty && FormattedTextBox._toolTipTextMenu) {
                 const marks = tx.storedMarks;
-                console.log(marks)
                 if (marks) { FormattedTextBox._toolTipTextMenu.mark_key_pressed(marks); }
             }
             this._applyingChange = true;
-- 
cgit v1.2.3-70-g09d2


From a7307ca3dc46782cc9e4cae4daa9b30911ace1dd Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Thu, 15 Aug 2019 23:19:33 -0400
Subject: tweaks for borderRounding in edge cases

---
 src/client/views/DocumentDecorations.tsx     | 3 ++-
 src/client/views/nodes/FormattedTextBox.scss | 4 ++--
 src/client/views/nodes/FormattedTextBox.tsx  | 2 +-
 3 files changed, 5 insertions(+), 4 deletions(-)

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

diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 9d877e5d6..d24762443 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -349,7 +349,8 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
             document.addEventListener("pointerup", this.onRadiusUp);
         }
         if (!this._isMoving) {
-            SelectionManager.SelectedDocuments().map(dv => dv.props.Document.borderRounding = Doc.GetProto(dv.props.Document).borderRounding = `0%`);
+            SelectionManager.SelectedDocuments().map(dv => dv.props.Document.layout instanceof Doc ? dv.props.Document.layout : dv.props.Document.isTemplate ? dv.props.Document : Doc.GetProto(dv.props.Document)).
+                map(d => d.borderRounding = "0%");
         }
     }
 
diff --git a/src/client/views/nodes/FormattedTextBox.scss b/src/client/views/nodes/FormattedTextBox.scss
index 247f7d1ea..d86aab09c 100644
--- a/src/client/views/nodes/FormattedTextBox.scss
+++ b/src/client/views/nodes/FormattedTextBox.scss
@@ -33,8 +33,8 @@
 }
 
 .formattedTextBox-inner-rounded {
-    height: calc(100% - 25px);
-    width: calc(100% - 40px);
+    height: calc(90%);
+    width: calc(85%);
     position: absolute;
     overflow: auto;
     top: 15;
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 516e36d5b..330bd135d 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -616,7 +616,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
             let dh = NumCast(this.props.Document.height, 0);
             let sh = scrBounds.height;
             const ChromeHeight = MainOverlayTextBox.Instance.ChromeHeight;
-            this.props.Document.height = (nh ? dh / nh * sh : sh) + (ChromeHeight ? ChromeHeight() : 0);
+            this.props.Document.height = Math.max(10, (nh ? dh / nh * sh : sh) + (ChromeHeight ? ChromeHeight() : 0));
             this.dataDoc.nativeHeight = nh ? sh : undefined;
         }
     }
-- 
cgit v1.2.3-70-g09d2


From b76c680013e98a4a8eb67a7371accf61cb8ef1aa Mon Sep 17 00:00:00 2001
From: Sam Wilkins <samwilkins333@gmail.com>
Date: Fri, 16 Aug 2019 16:01:34 -0400
Subject: linter errors fixed

---
 src/client/views/collections/CollectionStackingView.tsx | 2 +-
 src/client/views/nodes/DocumentView.tsx                 | 2 +-
 src/client/views/nodes/FormattedTextBox.tsx             | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

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

diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 288c38730..2e4f6aff5 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -63,7 +63,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
             setTimeout(() => this.props.Document.sectionHeaders = new List<SchemaHeaderField>(), 0);
             return new Map<SchemaHeaderField, Doc[]>();
         }
-        const sectionHeaders = this.sectionHeaders!;
+        const sectionHeaders = this.sectionHeaders;
         let fields = new Map<SchemaHeaderField, Doc[]>(sectionHeaders.map(sh => [sh, []] as [SchemaHeaderField, []]));
         this.filteredChildren.map(d => {
             let sectionValue = (d[this.sectionFilter] ? d[this.sectionFilter] : `NO ${this.sectionFilter.toUpperCase()} VALUE`) as object;
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 188a306ec..6bc8c4487 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -699,7 +699,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     onPointerLeave = (e: React.PointerEvent): void => { Doc.UnBrushDoc(this.props.Document); };
 
     isSelected = () => SelectionManager.IsSelected(this);
-    @action select = (ctrlPressed: boolean) => { SelectionManager.SelectDoc(this, ctrlPressed); }
+    @action select = (ctrlPressed: boolean) => { SelectionManager.SelectDoc(this, ctrlPressed); };
     @computed get nativeWidth() { return this.Document.nativeWidth || 0; }
     @computed get nativeHeight() { return this.Document.nativeHeight || 0; }
     @computed get onClickHandler() { return this.props.onClick ? this.props.onClick : this.Document.onClick; }
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 9d6c6861e..f7890e5a6 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -167,7 +167,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
             FormattedTextBox._toolTipTextMenu && (FormattedTextBox._toolTipTextMenu.HackToFixTextSelectionGlitch = false);
             if (state.selection.empty && FormattedTextBox._toolTipTextMenu) {
                 const marks = tx.storedMarks;
-                console.log(marks)
+                console.log(marks);
                 if (marks) { FormattedTextBox._toolTipTextMenu.mark_key_pressed(marks); }
             }
             this._applyingChange = true;
-- 
cgit v1.2.3-70-g09d2


From 7ea6b44b10e1bf23287ba33e0081cacbfc595780 Mon Sep 17 00:00:00 2001
From: Sam Wilkins <samwilkins333@gmail.com>
Date: Mon, 19 Aug 2019 14:58:02 -0400
Subject: seemed to fix syncing with remote google doc

---
 src/client/views/DocumentDecorations.tsx    | 14 ++++++++
 src/client/views/nodes/FormattedTextBox.tsx | 41 ++++++++++++++---------
 src/new_fields/RichTextField.ts             | 52 +++++++++++++----------------
 3 files changed, 63 insertions(+), 44 deletions(-)

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

diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 6616d5d58..963722fe3 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -1,5 +1,6 @@
 import { library } from '@fortawesome/fontawesome-svg-core';
 import { faLink, faTag } from '@fortawesome/free-solid-svg-icons';
+import * as fa from '@fortawesome/free-brands-svg-icons';
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
 import { action, computed, observable, reaction, runInAction } from "mobx";
 import { observer } from "mobx-react";
@@ -36,6 +37,7 @@ export const Flyout = higflyout.default;
 
 library.add(faLink);
 library.add(faTag);
+library.add(fa.faGoogleDrive as any);
 
 @observer
 export class DocumentDecorations extends React.Component<{}, { value: string }> {
@@ -618,6 +620,17 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
         );
     }
 
+    considerGoogleDoc = () => {
+        let thisDoc = SelectionManager.SelectedDocuments()[0].props.Document;
+        let canEmbed = thisDoc.data && thisDoc.data instanceof RichTextField;
+        if (!canEmbed) return (null);
+        return (
+            <div className={"linkButtonWrapper"}>
+                <FontAwesomeIcon className="documentdecorations-icon" icon="image" size="sm" />
+            </div>
+        );
+    }
+
     considerTooltip = () => {
         let thisDoc = SelectionManager.SelectedDocuments()[0].props.Document;
         let isTextDoc = thisDoc.data && thisDoc.data instanceof RichTextField;
@@ -768,6 +781,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
                     </div>
                     {this.metadataMenu}
                     {this.considerEmbed()}
+                    {this.considerGoogleDoc()}
                     {/* {this.considerTooltip()} */}
                 </div>
             </div >
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index ad29ce775..bc057bb5f 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -60,7 +60,7 @@ const richTextSchema = createSchema({
     documentText: "string"
 });
 
-const googleDocKey = "googleDocId";
+const googleDocId = "googleDocId";
 
 type RichTextDocument = makeInterface<[typeof richTextSchema]>;
 const RichTextDocument = makeInterface(richTextSchema);
@@ -84,6 +84,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
     private _proxyReactionDisposer: Opt<IReactionDisposer>;
     private dropDisposer?: DragManager.DragDropDisposer;
     public get CurrentDiv(): HTMLDivElement { return this._ref.current!; }
+    private isOpening = false;
     @observable _entered = false;
 
     @observable public static InputBoxOverlay?: FormattedTextBox = undefined;
@@ -295,17 +296,19 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
 
     pollExportedCounterpart = async () => {
         let dataDoc = Doc.GetProto(this.props.Document);
-        let documentId = StrCast(dataDoc[googleDocKey]);
+        let documentId = StrCast(dataDoc[googleDocId]);
         if (documentId) {
             let exportState = await GoogleApiClientUtils.Docs.read({ documentId });
             if (exportState) {
                 let data = Cast(dataDoc.data, RichTextField);
                 if (data) {
+                    this.isOpening = true;
                     dataDoc.data = new RichTextField(data[FromGoogleDocText](exportState));
                 }
             } else {
-                delete dataDoc[googleDocKey];
+                delete dataDoc[googleDocId];
             }
+            this.tryUpdateHeight();
         }
     }
 
@@ -346,9 +349,18 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
                 const field = this.dataDoc ? Cast(this.dataDoc[this.props.fieldKey], RichTextField) : undefined;
                 return field ? field.Data : `{"doc":{"type":"doc","content":[]},"selection":{"type":"text","anchor":0,"head":0}}`;
             },
-            field2 => {
-                this._editorView && !this._applyingChange &&
-                    this._editorView.updateState(EditorState.fromJSON(config, JSON.parse(field2)));
+            incomingValue => {
+                if (this._editorView && !this._applyingChange) {
+                    let updatedState = JSON.parse(incomingValue);
+                    this._editorView.updateState(EditorState.fromJSON(config, updatedState));
+                    // manually sets cursor selection at the end of the text on focus
+                    if (this.isOpening) {
+                        this.isOpening = false;
+                        let end = this._editorView.state.doc.content.size - 1;
+                        updatedState.selection = { type: "text", anchor: end, head: end };
+                        this._editorView.updateState(EditorState.fromJSON(config, updatedState));
+                    }
+                }
             }
         );
 
@@ -686,7 +698,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
             event: action(() => Doc.GetProto(this.props.Document).autoHeight = !BoolCast(this.props.Document.autoHeight)), icon: "expand-arrows-alt"
         });
         ContextMenu.Instance.addItem({ description: "Text Funcs...", subitems: subitems, icon: "text-height" });
-        if (!(googleDocKey in Doc.GetProto(this.props.Document))) {
+        if (!(googleDocId in Doc.GetProto(this.props.Document))) {
             ContextMenu.Instance.addItem({
                 description: "Export to Google Doc...",
                 event: this.updateGoogleDoc,
@@ -698,21 +710,18 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
     updateGoogleDoc = () => {
         let modes = GoogleApiClientUtils.Docs.WriteMode;
         let mode = modes.Replace;
-        let reference: Opt<GoogleApiClientUtils.Docs.Reference> = Cast(this.dataDoc[googleDocKey], "string");
+        let reference: Opt<GoogleApiClientUtils.Docs.Reference> = Cast(this.dataDoc[googleDocId], "string");
         if (!reference) {
             mode = modes.Insert;
             reference = {
                 title: StrCast(this.dataDoc.title),
-                handler: id => this.dataDoc[googleDocKey] = id
+                handler: id => this.dataDoc[googleDocId] = id
             };
         }
-        const data = Cast(this.dataDoc.data, RichTextField);
-        if (data) {
-            GoogleApiClientUtils.Docs.write({
-                mode,
-                content: data[ToGoogleDocText](),
-                reference
-            });
+        if (this._editorView) {
+            let data = Cast(this.dataDoc.data, RichTextField);
+            let content = data ? data[ToGoogleDocText]() : this._editorView.state.doc.textContent;
+            GoogleApiClientUtils.Docs.write({ reference, content, mode });
         }
     }
 
diff --git a/src/new_fields/RichTextField.ts b/src/new_fields/RichTextField.ts
index 8963682c3..ec08293e9 100644
--- a/src/new_fields/RichTextField.ts
+++ b/src/new_fields/RichTextField.ts
@@ -6,6 +6,8 @@ import { scriptingGlobal } from "../client/util/Scripting";
 
 export const ToGoogleDocText = Symbol("PlainText");
 export const FromGoogleDocText = Symbol("PlainText");
+const delimiter = "\n";
+const joiner = "";
 
 @scriptingGlobal
 @Deserializable("RichTextField")
@@ -27,45 +29,39 @@ export class RichTextField extends ObjectField {
     }
 
     [ToGoogleDocText]() {
-        let state = JSON.parse(this.Data);
-        let text = state.doc.textBetween(0, state.doc.content.size, "\n\n");
-        console.log(text);
+        // Because we're working with plain text, just concatenate all paragraphs
         let content = JSON.parse(this.Data).doc.content;
         let paragraphs = content.filter((item: any) => item.type === "paragraph");
-        let output = "";
-        for (let i = 0; i < paragraphs.length; i++) {
-            let paragraph = paragraphs[i];
-            let addNewLine = i > 0 ? paragraphs[i - 1].content : false;
-            if (paragraph.content) {
-                output += paragraph.content.map((block: any) => block.text).join("");
-            } else {
-                output += i === 0 ? "" : "\n";
-            }
-            addNewLine && (output += "\n");
-        }
-        return output;
+
+        // Functions to flatten ProseMirror paragraph objects (and their components) to plain text
+        // While this function already exists in state.doc.textBeteen(), it doesn't account for newlines 
+        let blockText = (block: any) => block.text;
+        let concatenateParagraph = (p: any) => (p.content ? p.content.map(blockText).join(joiner) : "") + delimiter;
+
+        // Concatentate paragraphs and string the result together. Trim the last newline, an artifact.
+        let textParagraphs = paragraphs.map(concatenateParagraph);
+        return textParagraphs.join(joiner).trimEnd(delimiter);
     }
 
     [FromGoogleDocText](plainText: string) {
-        let elements = plainText.split("\n");
+        // Remap the text, creating blocks split on newlines
+        let elements = plainText.split(delimiter);
+
+        // Google Docs adds in an extra carriage return automatically, so this counteracts it
         !elements[elements.length - 1].length && elements.pop();
+
+        // Preserve the current state, but re-write the content to be the blocks
         let parsed = JSON.parse(this.Data);
         parsed.doc.content = elements.map(text => {
             let paragraph: any = { type: "paragraph" };
-            if (text.length) {
-                paragraph.content = [{
-                    type: "text",
-                    marks: [],
-                    text
-                }];
-            }
+            text.length && (paragraph.content = [{ type: "text", marks: [], text }]); // An empty paragraph gets treated as a line break
             return paragraph;
         });
-        parsed.selection = {
-            type: "text",
-            anchor: 1,
-            head: 1
-        };
+
+        // If the new content is shorter than the previous content and selection is unchanged, may throw an out of bounds exception, so we reset it
+        parsed.selection = { type: "text", anchor: 1, head: 1 };
+
+        // Export the ProseMirror-compatible state object we've jsut built
         return JSON.stringify(parsed);
     }
 
-- 
cgit v1.2.3-70-g09d2


From df11d1afdb271b37618ab9e1d362b2f4a1145982 Mon Sep 17 00:00:00 2001
From: Sam Wilkins <samwilkins333@gmail.com>
Date: Mon, 19 Aug 2019 17:48:57 -0400
Subject: cleanup, pull push

---
 .../apis/google_docs/GoogleApiClientUtils.ts       | 27 +++++---
 src/client/views/DocumentDecorations.tsx           | 32 +++++++---
 src/client/views/collections/CollectionSubView.tsx | 14 +++-
 src/client/views/nodes/FormattedTextBox.tsx        | 74 +++++++++++++---------
 4 files changed, 98 insertions(+), 49 deletions(-)

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

diff --git a/src/client/apis/google_docs/GoogleApiClientUtils.ts b/src/client/apis/google_docs/GoogleApiClientUtils.ts
index 9d78b632d..55b4a76f8 100644
--- a/src/client/apis/google_docs/GoogleApiClientUtils.ts
+++ b/src/client/apis/google_docs/GoogleApiClientUtils.ts
@@ -27,8 +27,8 @@ export namespace GoogleApiClientUtils {
         export type CreationResult = Opt<DocumentId>;
         export type RetrievalResult = Opt<docs_v1.Schema$Document>;
         export type UpdateResult = Opt<docs_v1.Schema$BatchUpdateDocumentResponse>;
-        export type ReadLinesResult = Opt<string[]>;
-        export type ReadResult = Opt<string>;
+        export type ReadLinesResult = Opt<{ title?: string, bodyLines?: string[] }>;
+        export type ReadResult = { title?: string, body?: string };
 
         export interface CreateOptions {
             handler: IdHandler; // callback to process the documentId of the newly created Google Doc
@@ -148,18 +148,27 @@ export namespace GoogleApiClientUtils {
         };
 
         export const read = async (options: ReadOptions): Promise<ReadResult> => {
-            return retrieve(options).then(schema => {
-                return schema ? Utils.extractText(schema, options.removeNewlines) : undefined;
+            return retrieve(options).then(document => {
+                let result: ReadResult = {};
+                if (document) {
+                    let title = document.title;
+                    let body = Utils.extractText(document, options.removeNewlines);
+                    result = { title, body };
+                }
+                return result;
             });
         };
 
         export const readLines = async (options: ReadOptions): Promise<ReadLinesResult> => {
-            return retrieve(options).then(schema => {
-                if (!schema) {
-                    return undefined;
+            return retrieve(options).then(document => {
+                let result: ReadLinesResult = {};
+                if (document) {
+                    let title = document.title;
+                    let bodyLines = Utils.extractText(document).split("\n");
+                    options.removeNewlines && (bodyLines = bodyLines.filter(line => line.length));
+                    result = { title, bodyLines };
                 }
-                const lines = Utils.extractText(schema).split("\n");
-                return options.removeNewlines ? lines.filter(line => line.length) : lines;
+                return result;
             });
         };
 
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 963722fe3..80d4ecb9b 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -1,6 +1,5 @@
 import { library } from '@fortawesome/fontawesome-svg-core';
-import { faLink, faTag } from '@fortawesome/free-solid-svg-icons';
-import * as fa from '@fortawesome/free-brands-svg-icons';
+import { faLink, faTag, faArrowAltCircleDown, faArrowAltCircleUp } from '@fortawesome/free-solid-svg-icons';
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
 import { action, computed, observable, reaction, runInAction } from "mobx";
 import { observer } from "mobx-react";
@@ -37,7 +36,8 @@ export const Flyout = higflyout.default;
 
 library.add(faLink);
 library.add(faTag);
-library.add(fa.faGoogleDrive as any);
+library.add(faArrowAltCircleDown);
+library.add(faArrowAltCircleUp);
 
 @observer
 export class DocumentDecorations extends React.Component<{}, { value: string }> {
@@ -620,13 +620,28 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
         );
     }
 
-    considerGoogleDoc = () => {
+    considerGoogleDocsPush = () => {
         let thisDoc = SelectionManager.SelectedDocuments()[0].props.Document;
-        let canEmbed = thisDoc.data && thisDoc.data instanceof RichTextField;
-        if (!canEmbed) return (null);
+        let canPush = thisDoc.data && thisDoc.data instanceof RichTextField;
+        if (!canPush) return (null);
+        return (
+            <div className={"linkButtonWrapper"}>
+                <div title="Push to Google Docs" className="linkButton-linker" onClick={() => thisDoc.pushToGoogleDocsTrigger = !thisDoc.pushToGoogleDocsTrigger}>
+                    <FontAwesomeIcon className="documentdecorations-icon" icon="arrow-alt-circle-up" size="sm" />
+                </div>
+            </div>
+        );
+    }
+
+    considerGoogleDocsPull = () => {
+        let thisDoc = SelectionManager.SelectedDocuments()[0].props.Document;
+        let canPull = thisDoc.data && thisDoc.data instanceof RichTextField;
+        if (!canPull) return (null);
         return (
             <div className={"linkButtonWrapper"}>
-                <FontAwesomeIcon className="documentdecorations-icon" icon="image" size="sm" />
+                <div title="Pull From Google Docs" className="linkButton-linker" onClick={() => thisDoc.pullFromGoogleDocsTrigger = !thisDoc.pullFromGoogleDocsTrigger}>
+                    <FontAwesomeIcon className="documentdecorations-icon" icon="arrow-alt-circle-down" size="sm" />
+                </div>
             </div>
         );
     }
@@ -781,7 +796,8 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
                     </div>
                     {this.metadataMenu}
                     {this.considerEmbed()}
-                    {this.considerGoogleDoc()}
+                    {this.considerGoogleDocsPush()}
+                    {this.considerGoogleDocsPull()}
                     {/* {this.considerTooltip()} */}
                 </div>
             </div >
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 077f3f941..70c0632d1 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -16,7 +16,7 @@ import { DragManager } from "../../util/DragManager";
 import { undoBatch, UndoManager } from "../../util/UndoManager";
 import { DocComponent } from "../DocComponent";
 import { FieldViewProps } from "../nodes/FieldView";
-import { FormattedTextBox } from "../nodes/FormattedTextBox";
+import { FormattedTextBox, Blank } from "../nodes/FormattedTextBox";
 import { CollectionPDFView } from "./CollectionPDFView";
 import { CollectionVideoView } from "./CollectionVideoView";
 import { CollectionView } from "./CollectionView";
@@ -206,7 +206,17 @@ export function CollectionSubView<T>(schemaCtor: (doc: Doc) => T) {
                 this.props.addDocument(Docs.Create.VideoDocument(url, { ...options, title: url, width: 400, height: 315, nativeWidth: 600, nativeHeight: 472.5 }));
                 return;
             }
-
+            let matches: RegExpExecArray | null;
+            if ((matches = /(https:\/\/)?docs\.google\.com\/document\/d\/([^\\]+)\/edit/g.exec(text)) !== null) {
+                let newBox = Docs.Create.TextDocument({ ...options, width: 600, height: 400, title: "Fetching title from Google Docs..." });
+                let proto = newBox.proto!;
+                proto.autoHeight = true;
+                proto.googleDocId = matches[2];
+                proto.data = "Fetching contents from Google Docs...";
+                proto.backgroundColor = "#eeeeff";
+                this.props.addDocument(newBox);
+                return;
+            }
             let batch = UndoManager.StartBatch("collection view drop");
             let promises: Promise<void>[] = [];
             // tslint:disable-next-line:prefer-for-of
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index bc057bb5f..406c2c4a6 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -1,6 +1,6 @@
 import { library } from '@fortawesome/fontawesome-svg-core';
 import { faEdit, faSmile, faTextHeight, faUpload } from '@fortawesome/free-solid-svg-icons';
-import { action, IReactionDisposer, observable, reaction, runInAction, computed, Lambda, trace } from "mobx";
+import { action, IReactionDisposer, observable, reaction, runInAction, computed, Lambda, trace, untracked } from "mobx";
 import { observer } from "mobx-react";
 import { baseKeymap } from "prosemirror-commands";
 import { history } from "prosemirror-history";
@@ -47,6 +47,8 @@ library.add(faSmile, faTextHeight, faUpload);
 // FormattedTextBox: Displays an editable plain text node that maps to a specified Key of a Document
 //
 
+export const Blank = `{"doc":{"type":"doc","content":[]},"selection":{"type":"text","anchor":0,"head":0}}`;
+
 export interface FormattedTextBoxProps {
     isOverlay?: boolean;
     hideOnLeave?: boolean;
@@ -84,7 +86,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
     private _proxyReactionDisposer: Opt<IReactionDisposer>;
     private dropDisposer?: DragManager.DragDropDisposer;
     public get CurrentDiv(): HTMLDivElement { return this._ref.current!; }
-    private isOpening = false;
+    private isGoogleDocsUpdate = false;
     @observable _entered = false;
 
     @observable public static InputBoxOverlay?: FormattedTextBox = undefined;
@@ -290,28 +292,6 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
         }
     }
 
-    componentWillMount() {
-        this.pollExportedCounterpart();
-    }
-
-    pollExportedCounterpart = async () => {
-        let dataDoc = Doc.GetProto(this.props.Document);
-        let documentId = StrCast(dataDoc[googleDocId]);
-        if (documentId) {
-            let exportState = await GoogleApiClientUtils.Docs.read({ documentId });
-            if (exportState) {
-                let data = Cast(dataDoc.data, RichTextField);
-                if (data) {
-                    this.isOpening = true;
-                    dataDoc.data = new RichTextField(data[FromGoogleDocText](exportState));
-                }
-            } else {
-                delete dataDoc[googleDocId];
-            }
-            this.tryUpdateHeight();
-        }
-    }
-
     componentDidMount() {
         const config = {
             schema,
@@ -347,23 +327,32 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
         this._reactionDisposer = reaction(
             () => {
                 const field = this.dataDoc ? Cast(this.dataDoc[this.props.fieldKey], RichTextField) : undefined;
-                return field ? field.Data : `{"doc":{"type":"doc","content":[]},"selection":{"type":"text","anchor":0,"head":0}}`;
+                return field ? field.Data : Blank;
             },
             incomingValue => {
                 if (this._editorView && !this._applyingChange) {
                     let updatedState = JSON.parse(incomingValue);
                     this._editorView.updateState(EditorState.fromJSON(config, updatedState));
                     // manually sets cursor selection at the end of the text on focus
-                    if (this.isOpening) {
-                        this.isOpening = false;
+                    if (this.isGoogleDocsUpdate) {
+                        this.isGoogleDocsUpdate = false;
                         let end = this._editorView.state.doc.content.size - 1;
                         updatedState.selection = { type: "text", anchor: end, head: end };
                         this._editorView.updateState(EditorState.fromJSON(config, updatedState));
                     }
+                    this.tryUpdateHeight();
                 }
             }
         );
 
+        reaction(() => this.props.Document.pullFromGoogleDocsTrigger, () => {
+            this.pullFromGoogleDoc();
+        });
+
+        reaction(() => this.props.Document.pushToGoogleDocsTrigger, () => {
+            this.pushToGoogleDoc();
+        });
+
         this._textReactionDisposer = reaction(
             () => this.extensionDoc,
             () => {
@@ -391,6 +380,13 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
                 this.unhighlightSearchTerms();
             }
         }, { fireImmediately: true });
+
+        ["pushToGoogleDocsTrigger", "pullFromGoogleDocsTrigger"].map(key => {
+            let doc = this.props.Document;
+            if (doc[key] === undefined) {
+                untracked(() => doc[key] = false);
+            }
+        });
     }
 
     clipboardTextSerializer = (slice: Slice): string => {
@@ -644,7 +640,6 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
             this._undoTyping.end();
             this._undoTyping = undefined;
         }
-        this.updateGoogleDoc();
     }
     public _undoTyping?: UndoManager.Batch;
     onKeyPress = (e: React.KeyboardEvent) => {
@@ -701,13 +696,13 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
         if (!(googleDocId in Doc.GetProto(this.props.Document))) {
             ContextMenu.Instance.addItem({
                 description: "Export to Google Doc...",
-                event: this.updateGoogleDoc,
+                event: this.pushToGoogleDoc,
                 icon: "upload"
             });
         }
     }
 
-    updateGoogleDoc = () => {
+    pushToGoogleDoc = () => {
         let modes = GoogleApiClientUtils.Docs.WriteMode;
         let mode = modes.Replace;
         let reference: Opt<GoogleApiClientUtils.Docs.Reference> = Cast(this.dataDoc[googleDocId], "string");
@@ -725,6 +720,25 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
         }
     }
 
+    pullFromGoogleDoc = async () => {
+        let dataDoc = Doc.GetProto(this.props.Document);
+        let documentId = StrCast(dataDoc[googleDocId]);
+        if (documentId) {
+            let exportState = await GoogleApiClientUtils.Docs.read({ documentId });
+            if (exportState && exportState.body && exportState.title) {
+                let data = Cast(dataDoc.data, RichTextField);
+                if (data) {
+                    this.isGoogleDocsUpdate = true;
+                    dataDoc.data = new RichTextField(data[FromGoogleDocText](exportState.body));
+                    dataDoc.title = exportState.title;
+                }
+            } else {
+                delete dataDoc[googleDocId];
+            }
+        }
+    }
+
+
     render() {
         let self = this;
         let style = this.props.isOverlay ? "scroll" : "hidden";
-- 
cgit v1.2.3-70-g09d2


From 00cecb10d80bad8d717cd06ddc4bf156664b9f2d Mon Sep 17 00:00:00 2001
From: Sam Wilkins <samwilkins333@gmail.com>
Date: Mon, 19 Aug 2019 22:39:56 -0400
Subject: fixed push pull UI

---
 .../apis/google_docs/GoogleApiClientUtils.ts       |   3 +
 src/client/views/DocumentDecorations.tsx           |  14 ++-
 src/client/views/nodes/FormattedTextBox.tsx        | 122 +++++++++++----------
 src/new_fields/RichTextField.ts                    |   8 +-
 4 files changed, 81 insertions(+), 66 deletions(-)

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

diff --git a/src/client/apis/google_docs/GoogleApiClientUtils.ts b/src/client/apis/google_docs/GoogleApiClientUtils.ts
index 55b4a76f8..821c52270 100644
--- a/src/client/apis/google_docs/GoogleApiClientUtils.ts
+++ b/src/client/apis/google_docs/GoogleApiClientUtils.ts
@@ -4,6 +4,9 @@ import { RouteStore } from "../../../server/RouteStore";
 import { Opt } from "../../../new_fields/Doc";
 import { isArray } from "util";
 
+export const Pulls = "googleDocsPullCount";
+export const Pushes = "googleDocsPushCount";
+
 export namespace GoogleApiClientUtils {
 
     export namespace Docs {
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 80d4ecb9b..797b43add 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -30,6 +30,7 @@ import { ObjectField } from '../../new_fields/ObjectField';
 import { MetadataEntryMenu } from './MetadataEntryMenu';
 import { ImageBox } from './nodes/ImageBox';
 import { CurrentUserUtils } from '../../server/authentication/models/current_user_utils';
+import { Pulls, Pushes } from '../apis/google_docs/GoogleApiClientUtils';
 const higflyout = require("@hig/flyout");
 export const { anchorPoints } = higflyout;
 export const Flyout = higflyout.default;
@@ -626,7 +627,10 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
         if (!canPush) return (null);
         return (
             <div className={"linkButtonWrapper"}>
-                <div title="Push to Google Docs" className="linkButton-linker" onClick={() => thisDoc.pushToGoogleDocsTrigger = !thisDoc.pushToGoogleDocsTrigger}>
+                <div title="Push to Google Docs" className="linkButton-linker" onClick={() => {
+                    DocumentDecorations.hasPushedHack = false;
+                    thisDoc[Pushes] = NumCast(thisDoc[Pushes]) + 1;
+                }}>
                     <FontAwesomeIcon className="documentdecorations-icon" icon="arrow-alt-circle-up" size="sm" />
                 </div>
             </div>
@@ -639,13 +643,19 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
         if (!canPull) return (null);
         return (
             <div className={"linkButtonWrapper"}>
-                <div title="Pull From Google Docs" className="linkButton-linker" onClick={() => thisDoc.pullFromGoogleDocsTrigger = !thisDoc.pullFromGoogleDocsTrigger}>
+                <div title="Pull From Google Docs" className="linkButton-linker" onClick={() => {
+                    DocumentDecorations.hasPulledHack = false;
+                    thisDoc[Pulls] = NumCast(thisDoc[Pulls]) + 1;
+                }}>
                     <FontAwesomeIcon className="documentdecorations-icon" icon="arrow-alt-circle-down" size="sm" />
                 </div>
             </div>
         );
     }
 
+    public static hasPushedHack = false;
+    public static hasPulledHack = false;
+
     considerTooltip = () => {
         let thisDoc = SelectionManager.SelectedDocuments()[0].props.Document;
         let isTextDoc = thisDoc.data && thisDoc.data instanceof RichTextField;
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 406c2c4a6..d2eb71350 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -12,7 +12,7 @@ import { EditorView } from "prosemirror-view";
 import { Doc, Opt, DocListCast } from "../../../new_fields/Doc";
 import { Id, Copy } from '../../../new_fields/FieldSymbols';
 import { List } from '../../../new_fields/List';
-import { RichTextField, ToGoogleDocText, FromGoogleDocText } from "../../../new_fields/RichTextField";
+import { RichTextField, ToPlainText, FromPlainText } from "../../../new_fields/RichTextField";
 import { createSchema, listSpec, makeInterface } from "../../../new_fields/Schema";
 import { BoolCast, Cast, NumCast, StrCast, DateCast } from "../../../new_fields/Types";
 import { DocServer } from "../../DocServer";
@@ -30,16 +30,14 @@ import { ContextMenu } from "../../views/ContextMenu";
 import { ContextMenuProps } from '../ContextMenuItem';
 import { DocComponent } from "../DocComponent";
 import { InkingControl } from "../InkingControl";
-import { Templates } from '../Templates';
 import { FieldView, FieldViewProps } from "./FieldView";
 import "./FormattedTextBox.scss";
 import React = require("react");
-import { For } from 'babel-types';
 import { DateField } from '../../../new_fields/DateField';
 import { Utils } from '../../../Utils';
 import { MainOverlayTextBox } from '../MainOverlayTextBox';
-import { GoogleApiClientUtils } from '../../apis/google_docs/GoogleApiClientUtils';
-import * as diff from "diff";
+import { GoogleApiClientUtils, Pulls, Pushes } from '../../apis/google_docs/GoogleApiClientUtils';
+import { DocumentDecorations } from '../DocumentDecorations';
 
 library.add(faEdit);
 library.add(faSmile, faTextHeight, faUpload);
@@ -84,6 +82,8 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
     private _searchReactionDisposer?: Lambda;
     private _textReactionDisposer: Opt<IReactionDisposer>;
     private _proxyReactionDisposer: Opt<IReactionDisposer>;
+    private pullReactionDisposer: Opt<IReactionDisposer>;
+    private pushReactionDisposer: Opt<IReactionDisposer>;
     private dropDisposer?: DragManager.DragDropDisposer;
     public get CurrentDiv(): HTMLDivElement { return this._ref.current!; }
     private isGoogleDocsUpdate = false;
@@ -345,13 +345,25 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
             }
         );
 
-        reaction(() => this.props.Document.pullFromGoogleDocsTrigger, () => {
-            this.pullFromGoogleDoc();
-        });
+        this.pullReactionDisposer = reaction(
+            () => this.props.Document[Pulls],
+            () => {
+                if (!DocumentDecorations.hasPulledHack) {
+                    DocumentDecorations.hasPulledHack = true;
+                    this.pullFromGoogleDoc();
+                }
+            }
+        );
 
-        reaction(() => this.props.Document.pushToGoogleDocsTrigger, () => {
-            this.pushToGoogleDoc();
-        });
+        this.pushReactionDisposer = reaction(
+            () => this.props.Document[Pushes],
+            () => {
+                if (!DocumentDecorations.hasPushedHack) {
+                    DocumentDecorations.hasPushedHack = true;
+                    this.pushToGoogleDoc();
+                }
+            }
+        );
 
         this._textReactionDisposer = reaction(
             () => this.extensionDoc,
@@ -380,13 +392,44 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
                 this.unhighlightSearchTerms();
             }
         }, { fireImmediately: true });
+    }
 
-        ["pushToGoogleDocsTrigger", "pullFromGoogleDocsTrigger"].map(key => {
-            let doc = this.props.Document;
-            if (doc[key] === undefined) {
-                untracked(() => doc[key] = false);
-            }
-        });
+    pushToGoogleDoc = () => {
+        let modes = GoogleApiClientUtils.Docs.WriteMode;
+        let mode = modes.Replace;
+        let reference: Opt<GoogleApiClientUtils.Docs.Reference> = Cast(this.dataDoc[googleDocId], "string");
+        if (!reference) {
+            mode = modes.Insert;
+            reference = {
+                title: StrCast(this.dataDoc.title),
+                handler: id => this.dataDoc[googleDocId] = id
+            };
+        }
+        if (this._editorView) {
+            let data = Cast(this.dataDoc.data, RichTextField);
+            let content = data ? data[ToPlainText]() : this._editorView.state.doc.textContent;
+            GoogleApiClientUtils.Docs.write({ reference, content, mode });
+        }
+    }
+
+    pullFromGoogleDoc = async () => {
+        let dataDoc = Doc.GetProto(this.props.Document);
+        let documentId = StrCast(dataDoc[googleDocId]);
+        if (documentId) {
+            let exportState = await GoogleApiClientUtils.Docs.read({ documentId });
+            UndoManager.RunInBatch(() => {
+                if (exportState && exportState.body && exportState.title) {
+                    let data = Cast(dataDoc.data, RichTextField);
+                    if (data) {
+                        this.isGoogleDocsUpdate = true;
+                        dataDoc.data = new RichTextField(data[FromPlainText](exportState.body));
+                        dataDoc.title = exportState.title;
+                    }
+                } else {
+                    delete dataDoc[googleDocId];
+                }
+            }, Pulls);
+        }
     }
 
     clipboardTextSerializer = (slice: Slice): string => {
@@ -516,6 +559,8 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
         this._reactionDisposer && this._reactionDisposer();
         this._proxyReactionDisposer && this._proxyReactionDisposer();
         this._textReactionDisposer && this._textReactionDisposer();
+        this.pushReactionDisposer && this.pushReactionDisposer();
+        this.pullReactionDisposer && this.pullReactionDisposer();
     }
 
     onPointerDown = (e: React.PointerEvent): void => {
@@ -693,49 +738,6 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
             event: action(() => Doc.GetProto(this.props.Document).autoHeight = !BoolCast(this.props.Document.autoHeight)), icon: "expand-arrows-alt"
         });
         ContextMenu.Instance.addItem({ description: "Text Funcs...", subitems: subitems, icon: "text-height" });
-        if (!(googleDocId in Doc.GetProto(this.props.Document))) {
-            ContextMenu.Instance.addItem({
-                description: "Export to Google Doc...",
-                event: this.pushToGoogleDoc,
-                icon: "upload"
-            });
-        }
-    }
-
-    pushToGoogleDoc = () => {
-        let modes = GoogleApiClientUtils.Docs.WriteMode;
-        let mode = modes.Replace;
-        let reference: Opt<GoogleApiClientUtils.Docs.Reference> = Cast(this.dataDoc[googleDocId], "string");
-        if (!reference) {
-            mode = modes.Insert;
-            reference = {
-                title: StrCast(this.dataDoc.title),
-                handler: id => this.dataDoc[googleDocId] = id
-            };
-        }
-        if (this._editorView) {
-            let data = Cast(this.dataDoc.data, RichTextField);
-            let content = data ? data[ToGoogleDocText]() : this._editorView.state.doc.textContent;
-            GoogleApiClientUtils.Docs.write({ reference, content, mode });
-        }
-    }
-
-    pullFromGoogleDoc = async () => {
-        let dataDoc = Doc.GetProto(this.props.Document);
-        let documentId = StrCast(dataDoc[googleDocId]);
-        if (documentId) {
-            let exportState = await GoogleApiClientUtils.Docs.read({ documentId });
-            if (exportState && exportState.body && exportState.title) {
-                let data = Cast(dataDoc.data, RichTextField);
-                if (data) {
-                    this.isGoogleDocsUpdate = true;
-                    dataDoc.data = new RichTextField(data[FromGoogleDocText](exportState.body));
-                    dataDoc.title = exportState.title;
-                }
-            } else {
-                delete dataDoc[googleDocId];
-            }
-        }
     }
 
 
diff --git a/src/new_fields/RichTextField.ts b/src/new_fields/RichTextField.ts
index ec08293e9..ab58329f9 100644
--- a/src/new_fields/RichTextField.ts
+++ b/src/new_fields/RichTextField.ts
@@ -4,8 +4,8 @@ import { Deserializable } from "../client/util/SerializationHelper";
 import { Copy, ToScriptString } from "./FieldSymbols";
 import { scriptingGlobal } from "../client/util/Scripting";
 
-export const ToGoogleDocText = Symbol("PlainText");
-export const FromGoogleDocText = Symbol("PlainText");
+export const ToPlainText = Symbol("PlainText");
+export const FromPlainText = Symbol("PlainText");
 const delimiter = "\n";
 const joiner = "";
 
@@ -28,7 +28,7 @@ export class RichTextField extends ObjectField {
         return `new RichTextField("${this.Data}")`;
     }
 
-    [ToGoogleDocText]() {
+    [ToPlainText]() {
         // Because we're working with plain text, just concatenate all paragraphs
         let content = JSON.parse(this.Data).doc.content;
         let paragraphs = content.filter((item: any) => item.type === "paragraph");
@@ -43,7 +43,7 @@ export class RichTextField extends ObjectField {
         return textParagraphs.join(joiner).trimEnd(delimiter);
     }
 
-    [FromGoogleDocText](plainText: string) {
+    [FromPlainText](plainText: string) {
         // Remap the text, creating blocks split on newlines
         let elements = plainText.split(delimiter);
 
-- 
cgit v1.2.3-70-g09d2


From c92761206957aebdba1cc2e77f6b662ae42db847 Mon Sep 17 00:00:00 2001
From: Sam Wilkins <samwilkins333@gmail.com>
Date: Tue, 20 Aug 2019 01:44:18 -0400
Subject: interactive ui

---
 src/client/views/DocumentDecorations.tsx    | 84 +++++++++++++++++++++++------
 src/client/views/nodes/FormattedTextBox.tsx | 63 +++++++++++++++-------
 2 files changed, 112 insertions(+), 35 deletions(-)

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

diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 797b43add..1db452b45 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -1,5 +1,5 @@
-import { library } from '@fortawesome/fontawesome-svg-core';
-import { faLink, faTag, faArrowAltCircleDown, faArrowAltCircleUp } from '@fortawesome/free-solid-svg-icons';
+import { library, IconProp } from '@fortawesome/fontawesome-svg-core';
+import { faLink, faTag, faArrowAltCircleDown, faArrowAltCircleUp, faCheckCircle, faStopCircle, faCloudUploadAlt } from '@fortawesome/free-solid-svg-icons';
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
 import { action, computed, observable, reaction, runInAction } from "mobx";
 import { observer } from "mobx-react";
@@ -18,7 +18,7 @@ import { CollectionView } from "./collections/CollectionView";
 import './DocumentDecorations.scss';
 import { DocumentView, PositionDocument } from "./nodes/DocumentView";
 import { FieldView } from "./nodes/FieldView";
-import { FormattedTextBox } from "./nodes/FormattedTextBox";
+import { FormattedTextBox, GoogleRef } from "./nodes/FormattedTextBox";
 import { IconBox } from "./nodes/IconBox";
 import { LinkMenu } from "./nodes/LinkMenu";
 import { TemplateMenu } from "./TemplateMenu";
@@ -26,7 +26,6 @@ import { Template, Templates } from "./Templates";
 import React = require("react");
 import { RichTextField } from '../../new_fields/RichTextField';
 import { LinkManager } from '../util/LinkManager';
-import { ObjectField } from '../../new_fields/ObjectField';
 import { MetadataEntryMenu } from './MetadataEntryMenu';
 import { ImageBox } from './nodes/ImageBox';
 import { CurrentUserUtils } from '../../server/authentication/models/current_user_utils';
@@ -39,6 +38,11 @@ library.add(faLink);
 library.add(faTag);
 library.add(faArrowAltCircleDown);
 library.add(faArrowAltCircleUp);
+library.add(faStopCircle);
+library.add(faCheckCircle);
+library.add(faCloudUploadAlt);
+
+const cloud: IconProp = "cloud-upload-alt";
 
 @observer
 export class DocumentDecorations extends React.Component<{}, { value: string }> {
@@ -69,6 +73,52 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
     @observable private _removeIcon = false;
     @observable public Interacting = false;
 
+    @observable public pushIcon: IconProp = "arrow-alt-circle-up";
+    @observable public pullIcon: IconProp = "arrow-alt-circle-down";
+    @observable public pullColor: string = "white";
+    public pullColorAnimating = false;
+
+    private pullAnimating = false;
+    private pushAnimating = false;
+
+    public startPullOutcome = action((success: boolean) => {
+        if (this.pullAnimating) {
+            return;
+        }
+        this.pullAnimating = true;
+        this.pullIcon = success ? "check-circle" : "stop-circle";
+        setTimeout(() => runInAction(() => {
+            this.pullIcon = "arrow-alt-circle-down";
+            this.pullAnimating = false;
+        }), 1000);
+    });
+
+    public startPushOutcome = action((success: boolean) => {
+        if (this.pushAnimating) {
+            return;
+        }
+        this.pushAnimating = true;
+        this.pushIcon = success ? "check-circle" : "stop-circle";
+        setTimeout(() => runInAction(() => {
+            this.pushIcon = "arrow-alt-circle-up";
+            this.pushAnimating = false;
+        }), 1000);
+    });
+
+    public setPullState = (unchanged: boolean) => {
+        if (this.pullColorAnimating) {
+            return;
+        }
+        this.pullColorAnimating = true;
+        this.pullColor = unchanged ? "lawngreen" : "red";
+        setTimeout(() => {
+            runInAction(() => {
+                this.pullColor = "white";
+                this.pullColorAnimating = false;
+            });
+        }, 2000);
+    }
+
     constructor(props: Readonly<{}>) {
         super(props);
         DocumentDecorations.Instance = this;
@@ -621,33 +671,37 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
         );
     }
 
+    private get targetDoc() {
+        return SelectionManager.SelectedDocuments()[0].props.Document;
+    }
+
     considerGoogleDocsPush = () => {
-        let thisDoc = SelectionManager.SelectedDocuments()[0].props.Document;
-        let canPush = thisDoc.data && thisDoc.data instanceof RichTextField;
+        let canPush = this.targetDoc.data && this.targetDoc.data instanceof RichTextField;
         if (!canPush) return (null);
+        let published = Doc.GetProto(this.targetDoc)[GoogleRef] !== undefined;
+        let icon: IconProp = published ? (this.pushIcon as any) : (cloud as any);
         return (
             <div className={"linkButtonWrapper"}>
-                <div title="Push to Google Docs" className="linkButton-linker" onClick={() => {
+                <div title={`${published ? "Push" : "Publish"} to Google Docs`} className="linkButton-linker" onClick={() => {
                     DocumentDecorations.hasPushedHack = false;
-                    thisDoc[Pushes] = NumCast(thisDoc[Pushes]) + 1;
+                    this.targetDoc[Pushes] = NumCast(this.targetDoc[Pushes]) + 1;
                 }}>
-                    <FontAwesomeIcon className="documentdecorations-icon" icon="arrow-alt-circle-up" size="sm" />
+                    <FontAwesomeIcon className="documentdecorations-icon" icon={icon} size={published ? "sm" : "xs"} />
                 </div>
             </div>
         );
     }
 
     considerGoogleDocsPull = () => {
-        let thisDoc = SelectionManager.SelectedDocuments()[0].props.Document;
-        let canPull = thisDoc.data && thisDoc.data instanceof RichTextField;
-        if (!canPull) return (null);
+        let canPull = this.targetDoc.data && this.targetDoc.data instanceof RichTextField;
+        if (!canPull || !Doc.GetProto(this.targetDoc)[GoogleRef]) return (null);
         return (
             <div className={"linkButtonWrapper"}>
-                <div title="Pull From Google Docs" className="linkButton-linker" onClick={() => {
+                <div style={{ backgroundColor: this.pullColor, transition: "1s ease all" }} title="Pull From Google Docs" className="linkButton-linker" onClick={() => {
                     DocumentDecorations.hasPulledHack = false;
-                    thisDoc[Pulls] = NumCast(thisDoc[Pulls]) + 1;
+                    this.targetDoc[Pulls] = NumCast(this.targetDoc[Pulls]) + 1;
                 }}>
-                    <FontAwesomeIcon className="documentdecorations-icon" icon="arrow-alt-circle-down" size="sm" />
+                    <FontAwesomeIcon className="documentdecorations-icon" icon={this.pullIcon} size="sm" />
                 </div>
             </div>
         );
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index d2eb71350..33d222813 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -60,11 +60,13 @@ const richTextSchema = createSchema({
     documentText: "string"
 });
 
-const googleDocId = "googleDocId";
+export const GoogleRef = "googleDocId";
 
 type RichTextDocument = makeInterface<[typeof richTextSchema]>;
 const RichTextDocument = makeInterface(richTextSchema);
 
+type PullHandler = (exportState: GoogleApiClientUtils.Docs.ReadResult, dataDoc: Doc) => void;
+
 @observer
 export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTextBoxProps), RichTextDocument>(RichTextDocument) {
     public static LayoutString(fieldStr: string = "data") {
@@ -324,6 +326,8 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
                 }, { fireImmediately: true });
         }
 
+        this.pullFromGoogleDoc(this.checkState);
+
         this._reactionDisposer = reaction(
             () => {
                 const field = this.dataDoc ? Cast(this.dataDoc[this.props.fieldKey], RichTextField) : undefined;
@@ -350,7 +354,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
             () => {
                 if (!DocumentDecorations.hasPulledHack) {
                     DocumentDecorations.hasPulledHack = true;
-                    this.pullFromGoogleDoc();
+                    this.pullFromGoogleDoc(this.updateState);
                 }
             }
         );
@@ -394,44 +398,63 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
         }, { fireImmediately: true });
     }
 
-    pushToGoogleDoc = () => {
+    pushToGoogleDoc = async () => {
         let modes = GoogleApiClientUtils.Docs.WriteMode;
         let mode = modes.Replace;
-        let reference: Opt<GoogleApiClientUtils.Docs.Reference> = Cast(this.dataDoc[googleDocId], "string");
+        let reference: Opt<GoogleApiClientUtils.Docs.Reference> = Cast(this.dataDoc[GoogleRef], "string");
         if (!reference) {
             mode = modes.Insert;
             reference = {
                 title: StrCast(this.dataDoc.title),
-                handler: id => this.dataDoc[googleDocId] = id
+                handler: id => this.dataDoc[GoogleRef] = id
             };
         }
         if (this._editorView) {
             let data = Cast(this.dataDoc.data, RichTextField);
             let content = data ? data[ToPlainText]() : this._editorView.state.doc.textContent;
-            GoogleApiClientUtils.Docs.write({ reference, content, mode });
+            let response = await GoogleApiClientUtils.Docs.write({ reference, content, mode });
+            let pushSuccess = response !== undefined && !("errors" in response);
+            DocumentDecorations.Instance.startPushOutcome(pushSuccess);
         }
     }
 
-    pullFromGoogleDoc = async () => {
+    pullFromGoogleDoc = async (handler: PullHandler) => {
         let dataDoc = Doc.GetProto(this.props.Document);
-        let documentId = StrCast(dataDoc[googleDocId]);
+        let documentId = StrCast(dataDoc[GoogleRef]);
         if (documentId) {
             let exportState = await GoogleApiClientUtils.Docs.read({ documentId });
-            UndoManager.RunInBatch(() => {
-                if (exportState && exportState.body && exportState.title) {
-                    let data = Cast(dataDoc.data, RichTextField);
-                    if (data) {
-                        this.isGoogleDocsUpdate = true;
-                        dataDoc.data = new RichTextField(data[FromPlainText](exportState.body));
-                        dataDoc.title = exportState.title;
-                    }
-                } else {
-                    delete dataDoc[googleDocId];
-                }
-            }, Pulls);
+            UndoManager.RunInBatch(() => handler(exportState, dataDoc), Pulls);
         }
     }
 
+    updateState = (exportState: GoogleApiClientUtils.Docs.ReadResult, dataDoc: Doc) => {
+        let pullSuccess = false;
+        if (exportState !== undefined && exportState.body !== undefined && exportState.title !== undefined) {
+            let data = Cast(dataDoc.data, RichTextField);
+            if (data) {
+                pullSuccess = true;
+                this.isGoogleDocsUpdate = true;
+                dataDoc.data = new RichTextField(data[FromPlainText](exportState.body));
+                dataDoc.title = exportState.title;
+            }
+        } else {
+            delete dataDoc[GoogleRef];
+        }
+        DocumentDecorations.Instance.startPullOutcome(pullSuccess);
+    }
+
+    checkState = (exportState: GoogleApiClientUtils.Docs.ReadResult, dataDoc: Doc) => {
+        if (exportState !== undefined && exportState.body !== undefined && exportState.title !== undefined) {
+            let data = Cast(dataDoc.data, RichTextField);
+            if (data) {
+                let storedPlainText = data[ToPlainText]() + "\n";
+                let receivedPlainText = exportState.body;
+                DocumentDecorations.Instance.setPullState(storedPlainText === receivedPlainText);
+            }
+        }
+    }
+
+
     clipboardTextSerializer = (slice: Slice): string => {
         let text = "", separated = true;
         const from = 0, to = slice.content.size;
-- 
cgit v1.2.3-70-g09d2


From aa0e6f5ffc30fdffc3be13a1948981b754544a01 Mon Sep 17 00:00:00 2001
From: Sam Wilkins <samwilkins333@gmail.com>
Date: Tue, 20 Aug 2019 12:03:50 -0400
Subject: automation of pull push button visibility

---
 src/client/views/DocumentDecorations.tsx    |  3 +-
 src/client/views/nodes/FormattedTextBox.tsx | 61 +++++++++++++++++++----------
 2 files changed, 42 insertions(+), 22 deletions(-)

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

diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 1db452b45..05239073b 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -694,7 +694,8 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
 
     considerGoogleDocsPull = () => {
         let canPull = this.targetDoc.data && this.targetDoc.data instanceof RichTextField;
-        if (!canPull || !Doc.GetProto(this.targetDoc)[GoogleRef]) return (null);
+        let dataDoc = Doc.GetProto(this.targetDoc);
+        if (!canPull || !dataDoc[GoogleRef] || dataDoc.unchanged) return (null);
         return (
             <div className={"linkButtonWrapper"}>
                 <div style={{ backgroundColor: this.pullColor, transition: "1s ease all" }} title="Pull From Google Docs" className="linkButton-linker" onClick={() => {
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 33d222813..8a355a425 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -1,6 +1,6 @@
 import { library } from '@fortawesome/fontawesome-svg-core';
 import { faEdit, faSmile, faTextHeight, faUpload } from '@fortawesome/free-solid-svg-icons';
-import { action, IReactionDisposer, observable, reaction, runInAction, computed, Lambda, trace, untracked } from "mobx";
+import { action, IReactionDisposer, observable, reaction, runInAction, computed, Lambda, trace, untracked, autorun } from "mobx";
 import { observer } from "mobx-react";
 import { baseKeymap } from "prosemirror-commands";
 import { history } from "prosemirror-history";
@@ -399,32 +399,46 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
     }
 
     pushToGoogleDoc = async () => {
-        let modes = GoogleApiClientUtils.Docs.WriteMode;
-        let mode = modes.Replace;
-        let reference: Opt<GoogleApiClientUtils.Docs.Reference> = Cast(this.dataDoc[GoogleRef], "string");
-        if (!reference) {
-            mode = modes.Insert;
-            reference = {
-                title: StrCast(this.dataDoc.title),
-                handler: id => this.dataDoc[GoogleRef] = id
+        this.pullFromGoogleDoc(async (exportState: GoogleApiClientUtils.Docs.ReadResult, dataDoc: Doc) => {
+            let modes = GoogleApiClientUtils.Docs.WriteMode;
+            let mode = modes.Replace;
+            let reference: Opt<GoogleApiClientUtils.Docs.Reference> = Cast(this.dataDoc[GoogleRef], "string");
+            if (!reference) {
+                mode = modes.Insert;
+                reference = {
+                    title: StrCast(this.dataDoc.title),
+                    handler: id => this.dataDoc[GoogleRef] = id
+                };
+            }
+            let redo = async () => {
+                if (this._editorView && reference) {
+                    let data = Cast(this.dataDoc.data, RichTextField);
+                    let content = data ? data[ToPlainText]() : this._editorView.state.doc.textContent;
+                    let response = await GoogleApiClientUtils.Docs.write({ reference, content, mode });
+                    let pushSuccess = response !== undefined && !("errors" in response);
+                    dataDoc.unchanged = pushSuccess;
+                    DocumentDecorations.Instance.startPushOutcome(pushSuccess);
+                }
             };
-        }
-        if (this._editorView) {
-            let data = Cast(this.dataDoc.data, RichTextField);
-            let content = data ? data[ToPlainText]() : this._editorView.state.doc.textContent;
-            let response = await GoogleApiClientUtils.Docs.write({ reference, content, mode });
-            let pushSuccess = response !== undefined && !("errors" in response);
-            DocumentDecorations.Instance.startPushOutcome(pushSuccess);
-        }
+            let undo = () => {
+                let content = exportState.body;
+                if (reference && content) {
+                    GoogleApiClientUtils.Docs.write({ reference, content, mode });
+                }
+            };
+            UndoManager.AddEvent({ undo, redo });
+            redo();
+        });
     }
 
     pullFromGoogleDoc = async (handler: PullHandler) => {
-        let dataDoc = Doc.GetProto(this.props.Document);
+        let dataDoc = this.dataDoc;
         let documentId = StrCast(dataDoc[GoogleRef]);
+        let exportState: GoogleApiClientUtils.Docs.ReadResult = {};
         if (documentId) {
-            let exportState = await GoogleApiClientUtils.Docs.read({ documentId });
-            UndoManager.RunInBatch(() => handler(exportState, dataDoc), Pulls);
+            exportState = await GoogleApiClientUtils.Docs.read({ documentId });
         }
+        UndoManager.RunInBatch(() => handler(exportState, dataDoc), Pulls);
     }
 
     updateState = (exportState: GoogleApiClientUtils.Docs.ReadResult, dataDoc: Doc) => {
@@ -436,6 +450,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
                 this.isGoogleDocsUpdate = true;
                 dataDoc.data = new RichTextField(data[FromPlainText](exportState.body));
                 dataDoc.title = exportState.title;
+                dataDoc.unchanged = true;
             }
         } else {
             delete dataDoc[GoogleRef];
@@ -449,7 +464,11 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
             if (data) {
                 let storedPlainText = data[ToPlainText]() + "\n";
                 let receivedPlainText = exportState.body;
-                DocumentDecorations.Instance.setPullState(storedPlainText === receivedPlainText);
+                let storedTitle = dataDoc.title;
+                let receivedTitle = exportState.title;
+                let unchanged = storedPlainText === receivedPlainText && storedTitle === receivedTitle;
+                dataDoc.unchanged = unchanged;
+                DocumentDecorations.Instance.setPullState(unchanged);
             }
         }
     }
-- 
cgit v1.2.3-70-g09d2


From 700dfc5add1ecd9c2b1ecafcdc593ff821b7a6a6 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Tue, 20 Aug 2019 17:20:27 -0400
Subject: UI enhancements and other backend fixes for templates.

---
 src/client/util/DragManager.ts                     |  3 +-
 src/client/views/MetadataEntryMenu.scss            | 12 +++++
 src/client/views/MetadataEntryMenu.tsx             | 52 +++++++++++---------
 .../views/collections/CollectionStackingView.tsx   |  3 +-
 .../CollectionStackingViewFieldColumn.tsx          |  9 ++--
 src/client/views/collections/CollectionSubView.tsx |  2 +-
 .../views/collections/CollectionTreeView.tsx       |  3 ++
 .../views/collections/CollectionViewChromes.scss   |  1 -
 .../views/collections/CollectionViewChromes.tsx    | 57 +++++++++++-----------
 .../collectionFreeForm/CollectionFreeFormView.tsx  | 30 ++++++------
 src/client/views/nodes/DocumentContentsView.tsx    |  2 +-
 src/client/views/nodes/DocumentView.tsx            | 25 +++++++---
 src/client/views/nodes/FormattedTextBox.tsx        | 12 ++---
 src/client/views/nodes/ImageBox.tsx                |  7 +--
 src/new_fields/Doc.ts                              | 11 +++--
 15 files changed, 131 insertions(+), 98 deletions(-)

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

diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index 0b6d9b5e5..894b366ef 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -9,8 +9,6 @@ import { DocumentManager } from "./DocumentManager";
 import { LinkManager } from "./LinkManager";
 import { SelectionManager } from "./SelectionManager";
 import { SchemaHeaderField } from "../../new_fields/SchemaHeaderField";
-import { DocumentDecorations } from "../views/DocumentDecorations";
-import { NumberLiteralType } from "typescript";
 
 export type dropActionType = "alias" | "copy" | undefined;
 export function SetupDrag(
@@ -211,6 +209,7 @@ export namespace DragManager {
         dropAction: dropActionType;
         userDropAction: dropActionType;
         moveDocument?: MoveFunction;
+        applyAsTemplate?: boolean;
         [id: string]: any;
     }
 
diff --git a/src/client/views/MetadataEntryMenu.scss b/src/client/views/MetadataEntryMenu.scss
index bcfc9a82d..e28c4d0e0 100644
--- a/src/client/views/MetadataEntryMenu.scss
+++ b/src/client/views/MetadataEntryMenu.scss
@@ -1,8 +1,20 @@
 .metadataEntry-outerDiv {
     display: flex;
+    flex-direction: column;
     width: 300px;
 }
 
+.metadataEntry-keys {
+    max-height: 80;
+    overflow-y: auto; 
+    display: flex;
+    flex-direction: column;
+}
+.metadataEntry-inputArea {
+    display:flex;
+    flex-direction: row;
+}
+
 .react-autosuggest__container {
     position: relative;
 }
diff --git a/src/client/views/MetadataEntryMenu.tsx b/src/client/views/MetadataEntryMenu.tsx
index 36c240dd8..4a45eede9 100644
--- a/src/client/views/MetadataEntryMenu.tsx
+++ b/src/client/views/MetadataEntryMenu.tsx
@@ -1,11 +1,12 @@
 import * as React from 'react';
 import "./MetadataEntryMenu.scss";
 import { observer } from 'mobx-react';
-import { observable, action, runInAction, trace } from 'mobx';
+import { observable, action, runInAction, trace, computed, IReactionDisposer, reaction } from 'mobx';
 import { KeyValueBox } from './nodes/KeyValueBox';
 import { Doc, Field } from '../../new_fields/Doc';
 import * as Autosuggest from 'react-autosuggest';
 import { undoBatch } from '../util/UndoManager';
+import { emptyFunction } from '../../Utils';
 
 export type DocLike = Doc | Doc[] | Promise<Doc> | Promise<Doc[]>;
 export interface MetadataEntryProps {
@@ -18,7 +19,8 @@ export interface MetadataEntryProps {
 export class MetadataEntryMenu extends React.Component<MetadataEntryProps>{
     @observable private _currentKey: string = "";
     @observable private _currentValue: string = "";
-    @observable private suggestions: string[] = [];
+    @observable _allSuggestions: string[] = [];
+    _suggestionDispser: IReactionDisposer | undefined;
     private userModified = false;
 
     private autosuggestRef = React.createRef<Autosuggest>();
@@ -140,35 +142,39 @@ export class MetadataEntryMenu extends React.Component<MetadataEntryProps>{
     getSuggestionValue = (suggestion: string) => suggestion;
 
     renderSuggestion = (suggestion: string) => {
-        return <p>{suggestion}</p>;
+        return (null);
     }
+    componentDidMount() {
 
-    onSuggestionFetch = async ({ value }: { value: string }) => {
-        const sugg = await this.getKeySuggestions(value);
-        runInAction(() => {
-            this.suggestions = sugg;
-        });
+        this._suggestionDispser = reaction(() => this._currentKey,
+            () => this.getKeySuggestions(this._currentKey).then(action((s: string[]) => this._allSuggestions = s)),
+            { fireImmediately: true });
     }
-
-    @action
-    onSuggestionClear = () => {
-        this.suggestions = [];
+    componentWillUnmount() {
+        this._suggestionDispser && this._suggestionDispser();
     }
 
     render() {
         return (
             <div className="metadataEntry-outerDiv">
-                Key:
-                <Autosuggest inputProps={{ value: this._currentKey, onChange: this.onKeyChange }}
-                    getSuggestionValue={this.getSuggestionValue}
-                    suggestions={this.suggestions}
-                    alwaysRenderSuggestions
-                    renderSuggestion={this.renderSuggestion}
-                    onSuggestionsFetchRequested={this.onSuggestionFetch}
-                    onSuggestionsClearRequested={this.onSuggestionClear}
-                    ref={this.autosuggestRef} />
-                Value:
-                <input className="metadataEntry-input" value={this._currentValue} onChange={this.onValueChange} onKeyDown={this.onValueKeyDown} />
+                <div className="metadataEntry-inputArea">
+                    Key:
+                    <Autosuggest inputProps={{ value: this._currentKey, onChange: this.onKeyChange }}
+                        getSuggestionValue={this.getSuggestionValue}
+                        suggestions={[]}
+                        alwaysRenderSuggestions={false}
+                        renderSuggestion={this.renderSuggestion}
+                        onSuggestionsFetchRequested={emptyFunction}
+                        onSuggestionsClearRequested={emptyFunction}
+                        ref={this.autosuggestRef} />
+                    Value:
+                    <input className="metadataEntry-input" value={this._currentValue} onChange={this.onValueChange} onKeyDown={this.onValueKeyDown} />
+                </div>
+                <div className="metadataEntry-keys" >
+                    <ul>
+                        {this._allSuggestions.map(s => <li key={s} onClick={action(() => { this._currentKey = s; this.previewValue(); })} >{s}</li>)}
+                    </ul>
+                </div>
             </div>
         );
     }
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 1f7ef0689..c74c60d8f 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -160,7 +160,8 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
             previewScript={undefined}>
         </CollectionSchemaPreview>;
     }
-    getDocHeight(d: Doc) {
+    getDocHeight(d?: Doc) {
+        if (!d) return 0;
         let nw = NumCast(d.nativeWidth);
         let nh = NumCast(d.nativeHeight);
         if (!d.ignoreAspect && nw && nh) {
diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
index 74c7ef305..cc8476548 100644
--- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
+++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
@@ -78,11 +78,14 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
         let parent = this.props.parent;
         parent._docXfs.length = 0;
         return docs.map((d, i) => {
-            let pair = Doc.GetLayoutDataDocPair(parent.props.Document, parent.props.DataDoc, parent.props.fieldKey, d);
+            const pair = Doc.GetLayoutDataDocPair(parent.props.Document, parent.props.DataDoc, parent.props.fieldKey, d);
+            if (!pair.layout || pair.data instanceof Promise) {
+                return (null);
+            }
             let width = () => Math.min(d.nativeWidth && !d.ignoreAspect && !parent.props.Document.fillColumn ? d[WidthSym]() : Number.MAX_VALUE, parent.columnWidth / parent.numGroupColumns);
-            let height = () => parent.getDocHeight(pair.layout);
+            let height = () => parent.getDocHeight(pair!.layout);
             let dref = React.createRef<HTMLDivElement>();
-            let dxf = () => this.getDocTransform(pair.layout, dref.current!);
+            let dxf = () => this.getDocTransform(pair!.layout, dref.current!);
             this.props.parent._docXfs.push({ dxf: dxf, width: width, height: height });
             let rowSpan = Math.ceil((height() + parent.gridGap) / parent.gridGap);
             let style = parent.isStackingView ? { width: width(), margin: "auto", marginTop: i === 0 ? 0 : parent.gridGap, height: height() } : { gridRowEnd: `span ${rowSpan}` };
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index cfe3fefb3..818e76619 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -113,7 +113,7 @@ export function CollectionSubView<T>(schemaCtor: (doc: Doc) => T) {
         @undoBatch
         @action
         protected drop(e: Event, de: DragManager.DropEvent): boolean {
-            if (de.data instanceof DragManager.DocumentDragData) {
+            if (de.data instanceof DragManager.DocumentDragData && !de.data.applyAsTemplate) {
                 if (de.mods === "AltKey" && de.data.draggedDocuments.length) {
                     this.childDocs.map(doc =>
                         Doc.ApplyTemplateTo(de.data.draggedDocuments[0], doc, undefined)
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index b6a14238e..ebd385743 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -443,6 +443,9 @@ class TreeView extends React.Component<TreeViewProps> {
         let rowWidth = () => panelWidth() - 20;
         return docs.map((child, i) => {
             let pair = Doc.GetLayoutDataDocPair(containingCollection, dataDoc, key, child);
+            if (!pair.layout || pair.data instanceof Promise) {
+                return (null);
+            }
 
             let indent = i === 0 ? undefined : () => {
                 if (StrCast(docs[i - 1].layout).indexOf("CollectionView") !== -1) {
diff --git a/src/client/views/collections/CollectionViewChromes.scss b/src/client/views/collections/CollectionViewChromes.scss
index 595f079d1..f39bd877a 100644
--- a/src/client/views/collections/CollectionViewChromes.scss
+++ b/src/client/views/collections/CollectionViewChromes.scss
@@ -7,7 +7,6 @@
     z-index: 9001;
     transition: top .5s;
     background: lightgrey;
-    padding: 10px;
 
     .collectionViewChrome {
         display: grid;
diff --git a/src/client/views/collections/CollectionViewChromes.tsx b/src/client/views/collections/CollectionViewChromes.tsx
index b92bcc7cb..25b152d4e 100644
--- a/src/client/views/collections/CollectionViewChromes.tsx
+++ b/src/client/views/collections/CollectionViewChromes.tsx
@@ -1,30 +1,25 @@
-import * as React from "react";
-import { CollectionView } from "./CollectionView";
-import "./CollectionViewChromes.scss";
-import { CollectionViewType } from "./CollectionBaseView";
-import { undoBatch } from "../../util/UndoManager";
-import { action, observable, runInAction, computed, IObservable, IObservableValue, reaction, autorun } from "mobx";
-import { observer } from "mobx-react";
-import { Doc, DocListCast, FieldResult } from "../../../new_fields/Doc";
-import { DocLike } from "../MetadataEntryMenu";
-import * as Autosuggest from 'react-autosuggest';
-import { EditableView } from "../EditableView";
-import { StrCast, NumCast, BoolCast, Cast } from "../../../new_fields/Types";
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { action, computed, observable, runInAction } from "mobx";
+import { observer } from "mobx-react";
+import * as React from "react";
+import { Doc, DocListCast } from "../../../new_fields/Doc";
+import { Id } from "../../../new_fields/FieldSymbols";
+import { List } from "../../../new_fields/List";
+import { listSpec } from "../../../new_fields/Schema";
+import { ScriptField } from "../../../new_fields/ScriptField";
+import { BoolCast, Cast, NumCast, StrCast } from "../../../new_fields/Types";
 import { Utils } from "../../../Utils";
-import KeyRestrictionRow from "./KeyRestrictionRow";
+import { DragManager } from "../../util/DragManager";
 import { CompileScript } from "../../util/Scripting";
-import { ScriptField } from "../../../new_fields/ScriptField";
-import { CollectionSchemaView } from "./CollectionSchemaView";
+import { undoBatch } from "../../util/UndoManager";
+import { EditableView } from "../EditableView";
 import { COLLECTION_BORDER_WIDTH } from "../globalCssVariables.scss";
-import { listSpec } from "../../../new_fields/Schema";
-import { List } from "../../../new_fields/List";
-import { Id } from "../../../new_fields/FieldSymbols";
-import { threadId } from "worker_threads";
-import { DragManager } from "../../util/DragManager";
+import { DocLike } from "../MetadataEntryMenu";
+import { CollectionViewType } from "./CollectionBaseView";
+import { CollectionView } from "./CollectionView";
+import "./CollectionViewChromes.scss";
+import KeyRestrictionRow from "./KeyRestrictionRow";
 const datepicker = require('js-datepicker');
-import * as $ from 'jquery';
-import { firebasedynamiclinks } from "googleapis/build/src/apis/firebasedynamiclinks";
 
 interface CollectionViewChromeProps {
     CollectionView: CollectionView;
@@ -51,7 +46,6 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro
     @computed private get filterValue() { return Cast(this.props.CollectionView.props.Document.viewSpecScript, ScriptField); }
 
     private _picker: any;
-    private _datePickerElGuid = Utils.GenerateGuid();
 
     getFilters = (script: string) => {
         let re: any = /(!)?\(\(\(doc\.(\w+)\s+&&\s+\(doc\.\w+\s+as\s+\w+\)\.includes\(\"(\w+)\"\)/g;
@@ -91,11 +85,6 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro
     }
 
     componentDidMount = () => {
-        setTimeout(() => this._picker = datepicker("#" + this._datePickerElGuid, {
-            disabler: (date: Date) => date > new Date(),
-            onSelect: (instance: any, date: Date) => runInAction(() => this._dateValue = date),
-            dateSelected: new Date()
-        }), 1000);
 
         let fields: Filter[] = [];
         if (this.filterValue) {
@@ -306,6 +295,15 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro
         return true;
     }
 
+    datePickerRef = (node: HTMLInputElement) => {
+        if (node) {
+            this._picker = datepicker("#" + node.id, {
+                disabler: (date: Date) => date > new Date(),
+                onSelect: (instance: any, date: Date) => runInAction(() => this._dateValue = date),
+                dateSelected: new Date()
+            });
+        }
+    }
     render() {
         let collapsed = this.props.CollectionView.props.Document.chromeStatus !== "enabled";
         return (
@@ -366,7 +364,8 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro
                                         <option value="1y">1 year of</option>
                                     </select>
                                     <input className="collectionViewBaseChrome-viewSpecsMenu-rowRight"
-                                        id={this._datePickerElGuid}
+                                        id={Utils.GenerateGuid()}
+                                        ref={this.datePickerRef}
                                         value={this._dateValue instanceof Date ? this._dateValue.toLocaleDateString() : this._dateValue}
                                         onChange={(e) => runInAction(() => this._dateValue = e.target.value)}
                                         onPointerDown={this.openDatePicker}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index d69ece421..3be6aa3d3 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -622,20 +622,19 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
 
     getScale = () => this.Document.scale ? this.Document.scale : 1;
 
-    getChildDocumentViewProps(childDocLayout: Doc): DocumentViewProps {
-        let pair = Doc.GetLayoutDataDocPair(this.props.Document, this.props.DataDoc, this.props.fieldKey, childDocLayout);
+    getChildDocumentViewProps(childLayout: Doc, childData?: Doc): DocumentViewProps {
         return {
-            DataDoc: pair.data,
-            Document: pair.layout,
+            DataDoc: childData,
+            Document: childLayout,
             addDocument: this.props.addDocument,
             removeDocument: this.props.removeDocument,
             moveDocument: this.props.moveDocument,
             onClick: this.props.onClick,
-            ScreenToLocalTransform: pair.layout.z ? this.getTransformOverlay : this.getTransform,
+            ScreenToLocalTransform: childLayout.z ? this.getTransformOverlay : this.getTransform,
             renderDepth: this.props.renderDepth + 1,
-            selectOnLoad: pair.layout[Id] === this._selectOnLoaded,
-            PanelWidth: pair.layout[WidthSym],
-            PanelHeight: pair.layout[HeightSym],
+            selectOnLoad: childLayout[Id] === this._selectOnLoaded,
+            PanelWidth: childLayout[WidthSym],
+            PanelHeight: childLayout[HeightSym],
             ContentScaling: returnOne,
             ContainingCollectionView: this.props.CollectionView,
             focus: this.focusDocument,
@@ -745,12 +744,15 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
                     const pos = script ? this.getCalculatedPositions(script, { doc, index: prev.length, collection: this.Document, docs, state }) :
                         { x: Cast(doc.x, "number"), y: Cast(doc.y, "number"), z: Cast(doc.z, "number"), width: Cast(doc.width, "number"), height: Cast(doc.height, "number") };
                     state = pos.state === undefined ? state : pos.state;
-                    prev.push({
-                        ele: <CollectionFreeFormDocumentView key={doc[Id]}
-                            x={script ? pos.x : undefined} y={script ? pos.y : undefined}
-                            width={script ? pos.width : undefined} height={script ? pos.height : undefined} {...this.getChildDocumentViewProps(doc)} />,
-                        bounds: (pos.x !== undefined && pos.y !== undefined) ? { x: pos.x, y: pos.y, z: pos.z, width: NumCast(pos.width), height: NumCast(pos.height) } : undefined
-                    });
+                    let pair = Doc.GetLayoutDataDocPair(this.props.Document, this.props.DataDoc, this.props.fieldKey, doc);
+                    if (pair.layout && !(pair.data instanceof Promise)) {
+                        prev.push({
+                            ele: <CollectionFreeFormDocumentView key={doc[Id]}
+                                x={script ? pos.x : undefined} y={script ? pos.y : undefined}
+                                width={script ? pos.width : undefined} height={script ? pos.height : undefined} {...this.getChildDocumentViewProps(pair.layout, pair.data)} />,
+                            bounds: (pos.x !== undefined && pos.y !== undefined) ? { x: pos.x, y: pos.y, z: pos.z, width: NumCast(pos.width), height: NumCast(pos.height) } : undefined
+                        });
+                    }
                 }
             }
             return prev;
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index b901bdcfb..d77662355 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -68,7 +68,7 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & {
     }
 
     get dataDoc() {
-        if (this.props.DataDoc === undefined && this.props.Document.layout instanceof Doc) {
+        if (this.props.DataDoc === undefined && (this.props.Document.layout instanceof Doc || this.props.Document instanceof Promise)) {
             // if there is no dataDoc (ie, we're not rendering a template layout), but this document
             // has a template layout document, then we will render the template layout but use 
             // this document as the data document for the layout.
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 9e71094b0..fd53262d7 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -139,6 +139,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     private _lastTap: number = 0;
     private _doubleTap = false;
     private _hitExpander = false;
+    private _hitTemplateDrag = false;
     private _mainCont = React.createRef<HTMLDivElement>();
     private _dropDisposer?: DragManager.DragDropDisposer;
     _animateToIconDisposer?: IReactionDisposer;
@@ -228,7 +229,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     }
 
     get dataDoc() {
-        if (this.props.DataDoc === undefined && this.props.Document.layout instanceof Doc) {
+        if (this.props.DataDoc === undefined && (this.props.Document.layout instanceof Doc || this.props.Document instanceof Promise)) {
             // if there is no dataDoc (ie, we're not rendering a temlplate layout), but this document
             // has a template layout document, then we will render the template layout but use 
             // this document as the data document for the layout.
@@ -236,7 +237,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         }
         return this.props.DataDoc !== this.props.Document ? this.props.DataDoc : undefined;
     }
-    startDragging(x: number, y: number, dropAction: dropActionType, dragSubBullets: boolean) {
+    startDragging(x: number, y: number, dropAction: dropActionType, dragSubBullets: boolean, applyAsTemplate?: boolean) {
         if (this._mainCont.current) {
             let allConnected = [this.props.Document, ...(dragSubBullets ? DocListCast(this.props.Document.subBulletDocs) : [])];
             let alldataConnected = [this.dataDoc, ...(dragSubBullets ? DocListCast(this.props.Document.subBulletDocs) : [])];
@@ -247,6 +248,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
             dragData.xOffset = xoff;
             dragData.yOffset = yoff;
             dragData.moveDocument = this.props.moveDocument;
+            dragData.applyAsTemplate = applyAsTemplate;
             DragManager.StartDocumentDrag([this._mainCont.current], dragData, x, y, {
                 handlers: {
                     dragComplete: action(emptyFunction)
@@ -377,15 +379,19 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
             }
         }
     }
+
+
     onPointerDown = (e: React.PointerEvent): void => {
         if (e.nativeEvent.cancelBubble) return;
         this._downX = e.clientX;
         this._downY = e.clientY;
         this._hitExpander = DocListCast(this.props.Document.subBulletDocs).length > 0;
-        // if (e.shiftKey && e.buttons === 1 && CollectionDockingView.Instance) {
-        // CollectionDockingView.Instance.StartOtherDrag(e, [Doc.MakeAlias(this.props.Document)], [this.dataDoc]);
-        // e.stopPropagation();
-        // } else {
+        this._hitTemplateDrag = false;
+        for (let element = (e.target as any); element && !this._hitTemplateDrag; element = element.parentElement) {
+            if (element.className && element.className.toString() === "collectionViewBaseChrome-collapse") {
+                this._hitTemplateDrag = true;
+            }
+        }
         if (this.active) e.stopPropagation(); // events stop at the lowest document that is active.  
         document.removeEventListener("pointermove", this.onPointerMove);
         document.addEventListener("pointermove", this.onPointerMove);
@@ -399,7 +405,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                 if (!e.altKey && !this.topMost && e.buttons === 1 && !BoolCast(this.props.Document.lockedPosition)) {
                     document.removeEventListener("pointermove", this.onPointerMove);
                     document.removeEventListener("pointerup", this.onPointerUp);
-                    this.startDragging(this._downX, this._downY, e.ctrlKey || e.altKey ? "alias" : undefined, this._hitExpander);
+                    this.startDragging(this._downX, this._downY, e.ctrlKey || e.altKey ? "alias" : undefined, this._hitExpander, this._hitTemplateDrag);
                 }
             }
             e.stopPropagation(); // doesn't actually stop propagation since all our listeners are listening to events on 'document'  however it does mark the event as cancelBubble=true which we test for in the move event handlers
@@ -457,6 +463,10 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
 
             DocUtils.MakeLink(annotationDoc, targetDoc, this.props.ContainingCollectionView!.props.Document, `Link from ${StrCast(annotationDoc.title)}`);
         }
+        if (de.data instanceof DragManager.DocumentDragData && de.data.applyAsTemplate) {
+            Doc.ApplyTemplateTo(de.data.draggedDocuments[0], this.props.Document, this.props.DataDoc);
+            e.stopPropagation();
+        }
         if (de.data instanceof DragManager.LinkDragData) {
             let sourceDoc = de.data.linkSourceDocument;
             let destDoc = this.props.Document;
@@ -679,7 +689,6 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
             cm.addItem({ description: "Share...", subitems: usersMenu, icon: "share" });
             if (!ClientUtils.RELEASE) {
                 let setWriteMode = (mode: DocServer.WriteMode) => {
-                    console.log(DocServer.WriteMode[mode]);
                     DocServer.AclsMode = mode;
                     const mode1 = mode;
                     const mode2 = mode === DocServer.WriteMode.Default ? mode : DocServer.WriteMode.Playground;
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index f7890e5a6..0e347ca67 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -167,7 +167,6 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
             FormattedTextBox._toolTipTextMenu && (FormattedTextBox._toolTipTextMenu.HackToFixTextSelectionGlitch = false);
             if (state.selection.empty && FormattedTextBox._toolTipTextMenu) {
                 const marks = tx.storedMarks;
-                console.log(marks);
                 if (marks) { FormattedTextBox._toolTipTextMenu.mark_key_pressed(marks); }
             }
             this._applyingChange = true;
@@ -296,10 +295,10 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
                 this._editorView.updateState(EditorState.fromJSON(config, JSON.parse(field2)))
         );
 
-        this.props.isOverlay && (this._heightReactionDisposer = reaction(
+        this._heightReactionDisposer = reaction(
             () => this.props.Document[WidthSym](),
             () => this.tryUpdateHeight()
-        ));
+        );
 
         this._textReactionDisposer = reaction(
             () => this.extensionDoc,
@@ -448,8 +447,8 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
         if (this.props.selectOnLoad) {
             if (!this.props.isOverlay) this.props.select(false);
             else this._editorView!.focus();
-            this.tryUpdateHeight();
         }
+        this.tryUpdateHeight();
     }
 
     componentWillUnmount() {
@@ -610,9 +609,10 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
 
     @action
     tryUpdateHeight() {
-        if (this.props.Document.autoHeight && this.props.isOverlay) {
+        if (this.props.Document.autoHeight && this._ref.current!.scrollHeight !== 0) {
+            console.log("DT = " + this.props.Document.title + " " + this._ref.current!.clientHeight + " " + this._ref.current!.scrollHeight + " " + this._ref.current!.textContent)
             let xf = this._ref.current!.getBoundingClientRect();
-            let scrBounds = this.props.ScreenToLocalTransform().transformBounds(0, 0, xf.width, xf.height);
+            let scrBounds = this.props.ScreenToLocalTransform().transformBounds(0, 0, xf.width, this._ref.current!.textContent === "" ? 35 : this._ref.current!.scrollHeight);
             let nh = this.props.Document.isTemplate ? 0 : NumCast(this.dataDoc.nativeHeight, 0);
             let dh = NumCast(this.props.Document.height, 0);
             let sh = scrBounds.height;
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 708e00576..6fc94a140 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -89,10 +89,7 @@ export class ImageBox extends DocComponent<FieldViewProps, ImageDocument>(ImageD
     drop = (e: Event, de: DragManager.DropEvent) => {
         if (de.data instanceof DragManager.DocumentDragData) {
             de.data.droppedDocuments.forEach(action((drop: Doc) => {
-                if (de.mods === "CtrlKey") {
-                    Doc.ApplyTemplateTo(drop, this.props.Document, this.props.DataDoc);
-                    e.stopPropagation();
-                } else if (de.mods === "AltKey" && /*this.dataDoc !== this.props.Document &&*/ drop.data instanceof ImageField) {
+                if (de.mods === "AltKey" && /*this.dataDoc !== this.props.Document &&*/ drop.data instanceof ImageField) {
                     Doc.GetProto(this.dataDoc)[this.props.fieldKey] = new ImageField(drop.data.url);
                     e.stopPropagation();
                 } else if (de.mods === "MetaKey") {
@@ -321,7 +318,7 @@ export class ImageBox extends DocComponent<FieldViewProps, ImageDocument>(ImageD
                 let rotation = NumCast(this.dataDoc.rotation) % 180;
                 let realsize = rotation === 90 || rotation === 270 ? { height: size.width, width: size.height } : size;
                 let aspect = realsize.height / realsize.width;
-                if (Math.abs(NumCast(layoutdoc.height) - realsize.height) > 1 || Math.abs(NumCast(layoutdoc.width) - realsize.width) > 1) {
+                if (layoutdoc.nativeHeight !== 0 && layoutdoc.nativeWidth !== 0 && (Math.abs(NumCast(layoutdoc.height) - realsize.height) > 1 || Math.abs(NumCast(layoutdoc.width) - realsize.width) > 1)) {
                     setTimeout(action(() => {
                         layoutdoc.height = layoutdoc[WidthSym]() * aspect;
                         layoutdoc.nativeHeight = realsize.height;
diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts
index 31f1f7a12..ca05dfa45 100644
--- a/src/new_fields/Doc.ts
+++ b/src/new_fields/Doc.ts
@@ -446,20 +446,23 @@ export namespace Doc {
         if (expandedTemplateLayout instanceof Doc) {
             return expandedTemplateLayout;
         }
+        if (expandedTemplateLayout instanceof Promise) {
+            return undefined;
+        }
         let expandedLayoutFieldKey = "Layout[" + templateLayoutDoc[Id] + "]";
         expandedTemplateLayout = dataDoc[expandedLayoutFieldKey];
         if (expandedTemplateLayout instanceof Doc) {
             return expandedTemplateLayout;
         }
         if (expandedTemplateLayout === undefined) {
-            setTimeout(() =>
-                dataDoc[expandedLayoutFieldKey] = Doc.MakeDelegate(templateLayoutDoc, undefined, "[" + templateLayoutDoc.title + "]"), 0);
+            setTimeout(() => dataDoc[expandedLayoutFieldKey] === undefined &&
+                (dataDoc[expandedLayoutFieldKey] = Doc.MakeDelegate(templateLayoutDoc, undefined, "[" + templateLayoutDoc.title + "]")), 0);
         }
-        return templateLayoutDoc; // use the templateLayout when it's not a template or the expandedTemplate is pending.
+        return undefined; // use the templateLayout when it's not a template or the expandedTemplate is pending.
     }
 
     export function GetLayoutDataDocPair(doc: Doc, dataDoc: Doc | undefined, fieldKey: string, childDocLayout: Doc) {
-        let layoutDoc = childDocLayout;
+        let layoutDoc: Doc | undefined = childDocLayout;
         let resolvedDataDoc = !doc.isTemplate && dataDoc !== doc && dataDoc ? Doc.GetDataDoc(dataDoc) : undefined;
         if (resolvedDataDoc && Doc.WillExpandTemplateLayout(childDocLayout, resolvedDataDoc)) {
             Doc.UpdateDocumentExtensionForField(resolvedDataDoc, fieldKey);
-- 
cgit v1.2.3-70-g09d2


From dc587b0fb493d869e6cd38fa94b81105da4fbaab Mon Sep 17 00:00:00 2001
From: Sam Wilkins <samwilkins333@gmail.com>
Date: Tue, 20 Aug 2019 20:03:08 -0400
Subject: finished UI

---
 src/client/views/DocumentDecorations.scss   |  6 +-
 src/client/views/DocumentDecorations.tsx    | 92 ++++++++++++++++++-----------
 src/client/views/nodes/FormattedTextBox.tsx |  3 +-
 src/new_fields/RichTextField.ts             |  7 ++-
 4 files changed, 67 insertions(+), 41 deletions(-)

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

diff --git a/src/client/views/DocumentDecorations.scss b/src/client/views/DocumentDecorations.scss
index 0b7411fca..ef7159370 100644
--- a/src/client/views/DocumentDecorations.scss
+++ b/src/client/views/DocumentDecorations.scss
@@ -255,4 +255,8 @@ $linkGap : 3px;
     input {
         margin-right: 10px;
     }
-}
\ No newline at end of file
+}
+
+@-moz-keyframes spin { 100% { -moz-transform: rotate(360deg); } }
+@-webkit-keyframes spin { 100% { -webkit-transform: rotate(360deg); } }
+@keyframes spin { 100% { -webkit-transform: rotate(360deg); transform: rotate(360deg); } }
\ No newline at end of file
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 05239073b..7645af054 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -1,5 +1,5 @@
 import { library, IconProp } from '@fortawesome/fontawesome-svg-core';
-import { faLink, faTag, faArrowAltCircleDown, faArrowAltCircleUp, faCheckCircle, faStopCircle, faCloudUploadAlt } from '@fortawesome/free-solid-svg-icons';
+import { faLink, faTag, faArrowAltCircleDown, faArrowAltCircleUp, faCheckCircle, faStopCircle, faCloudUploadAlt, faSyncAlt } from '@fortawesome/free-solid-svg-icons';
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
 import { action, computed, observable, reaction, runInAction } from "mobx";
 import { observer } from "mobx-react";
@@ -41,8 +41,10 @@ library.add(faArrowAltCircleUp);
 library.add(faStopCircle);
 library.add(faCheckCircle);
 library.add(faCloudUploadAlt);
+library.add(faSyncAlt);
 
 const cloud: IconProp = "cloud-upload-alt";
+const fetch: IconProp = "sync-alt";
 
 @observer
 export class DocumentDecorations extends React.Component<{}, { value: string }> {
@@ -76,48 +78,47 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
     @observable public pushIcon: IconProp = "arrow-alt-circle-up";
     @observable public pullIcon: IconProp = "arrow-alt-circle-down";
     @observable public pullColor: string = "white";
+    @observable public isAnimatingFetch = false;
     public pullColorAnimating = false;
 
     private pullAnimating = false;
     private pushAnimating = false;
 
     public startPullOutcome = action((success: boolean) => {
-        if (this.pullAnimating) {
-            return;
+        if (!this.pullAnimating) {
+            this.pullAnimating = true;
+            this.pullIcon = success ? "check-circle" : "stop-circle";
+            setTimeout(() => runInAction(() => {
+                this.pullIcon = "arrow-alt-circle-down";
+                this.pullAnimating = false;
+            }), 1000);
         }
-        this.pullAnimating = true;
-        this.pullIcon = success ? "check-circle" : "stop-circle";
-        setTimeout(() => runInAction(() => {
-            this.pullIcon = "arrow-alt-circle-down";
-            this.pullAnimating = false;
-        }), 1000);
     });
 
     public startPushOutcome = action((success: boolean) => {
-        if (this.pushAnimating) {
-            return;
+        if (!this.pushAnimating) {
+            this.pushAnimating = true;
+            this.pushIcon = success ? "check-circle" : "stop-circle";
+            setTimeout(() => runInAction(() => {
+                this.pushIcon = "arrow-alt-circle-up";
+                this.pushAnimating = false;
+            }), 1000);
         }
-        this.pushAnimating = true;
-        this.pushIcon = success ? "check-circle" : "stop-circle";
-        setTimeout(() => runInAction(() => {
-            this.pushIcon = "arrow-alt-circle-up";
-            this.pushAnimating = false;
-        }), 1000);
     });
 
-    public setPullState = (unchanged: boolean) => {
-        if (this.pullColorAnimating) {
-            return;
+    public setPullState = action((unchanged: boolean) => {
+        this.isAnimatingFetch = false;
+        if (!this.pullColorAnimating) {
+            this.pullColorAnimating = true;
+            this.pullColor = unchanged ? "lawngreen" : "red";
+            setTimeout(this.clearPullColor, 1000);
         }
-        this.pullColorAnimating = true;
-        this.pullColor = unchanged ? "lawngreen" : "red";
-        setTimeout(() => {
-            runInAction(() => {
-                this.pullColor = "white";
-                this.pullColorAnimating = false;
-            });
-        }, 2000);
-    }
+    });
+
+    private clearPullColor = action(() => {
+        this.pullColor = "white";
+        this.pullColorAnimating = false;
+    });
 
     constructor(props: Readonly<{}>) {
         super(props);
@@ -679,7 +680,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
         let canPush = this.targetDoc.data && this.targetDoc.data instanceof RichTextField;
         if (!canPush) return (null);
         let published = Doc.GetProto(this.targetDoc)[GoogleRef] !== undefined;
-        let icon: IconProp = published ? (this.pushIcon as any) : (cloud as any);
+        let icon: IconProp = published ? (this.pushIcon as any) : cloud;
         return (
             <div className={"linkButtonWrapper"}>
                 <div title={`${published ? "Push" : "Publish"} to Google Docs`} className="linkButton-linker" onClick={() => {
@@ -695,14 +696,33 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
     considerGoogleDocsPull = () => {
         let canPull = this.targetDoc.data && this.targetDoc.data instanceof RichTextField;
         let dataDoc = Doc.GetProto(this.targetDoc);
-        if (!canPull || !dataDoc[GoogleRef] || dataDoc.unchanged) return (null);
+        if (!canPull || !dataDoc[GoogleRef]) return (null);
+        let icon = !dataDoc.unchanged ? (this.pullIcon as any) : fetch;
+        let animation = this.isAnimatingFetch ? "spin 0.5s linear infinite" : "none";
         return (
             <div className={"linkButtonWrapper"}>
-                <div style={{ backgroundColor: this.pullColor, transition: "1s ease all" }} title="Pull From Google Docs" className="linkButton-linker" onClick={() => {
-                    DocumentDecorations.hasPulledHack = false;
-                    this.targetDoc[Pulls] = NumCast(this.targetDoc[Pulls]) + 1;
-                }}>
-                    <FontAwesomeIcon className="documentdecorations-icon" icon={this.pullIcon} size="sm" />
+                <div
+                    title="Pull From Google Docs"
+                    className="linkButton-linker"
+                    style={{
+                        backgroundColor: this.pullColor,
+                        transition: "0.2s ease all"
+                    }}
+                    onClick={() => {
+                        this.clearPullColor();
+                        DocumentDecorations.hasPulledHack = false;
+                        this.targetDoc[Pulls] = NumCast(this.targetDoc[Pulls]) + 1;
+                        dataDoc.unchanged && runInAction(() => this.isAnimatingFetch = true);
+                    }}>
+                    <FontAwesomeIcon
+                        style={{
+                            WebkitAnimation: animation,
+                            MozAnimation: animation
+                        }}
+                        className="documentdecorations-icon"
+                        icon={icon}
+                        size="sm"
+                    />
                 </div>
             </div>
         );
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 8a355a425..e06be7079 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -354,7 +354,8 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
             () => {
                 if (!DocumentDecorations.hasPulledHack) {
                     DocumentDecorations.hasPulledHack = true;
-                    this.pullFromGoogleDoc(this.updateState);
+                    let unchanged = this.dataDoc.unchanged;
+                    this.pullFromGoogleDoc(unchanged ? this.checkState : this.updateState);
                 }
             }
         );
diff --git a/src/new_fields/RichTextField.ts b/src/new_fields/RichTextField.ts
index ab58329f9..cae5623e6 100644
--- a/src/new_fields/RichTextField.ts
+++ b/src/new_fields/RichTextField.ts
@@ -38,9 +38,10 @@ export class RichTextField extends ObjectField {
         let blockText = (block: any) => block.text;
         let concatenateParagraph = (p: any) => (p.content ? p.content.map(blockText).join(joiner) : "") + delimiter;
 
-        // Concatentate paragraphs and string the result together. Trim the last newline, an artifact.
-        let textParagraphs = paragraphs.map(concatenateParagraph);
-        return textParagraphs.join(joiner).trimEnd(delimiter);
+        // Concatentate paragraphs and string the result together
+        let textParagraphs: string[] = paragraphs.map(concatenateParagraph);
+        let plainText = textParagraphs.join(joiner);
+        return plainText.substring(0, plainText.length - 1);
     }
 
     [FromPlainText](plainText: string) {
-- 
cgit v1.2.3-70-g09d2


From 820ad7343816ee9d5881eefdbcbe8783fe903257 Mon Sep 17 00:00:00 2001
From: Sam Wilkins <samwilkins333@gmail.com>
Date: Tue, 20 Aug 2019 21:07:43 -0400
Subject: animation fix

---
 src/client/views/nodes/FormattedTextBox.tsx | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

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

diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 2705fac14..d4cbb5116 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -1,6 +1,6 @@
 import { library } from '@fortawesome/fontawesome-svg-core';
 import { faEdit, faSmile, faTextHeight, faUpload } from '@fortawesome/free-solid-svg-icons';
-import { action, computed, IReactionDisposer, Lambda, observable, reaction } from "mobx";
+import { action, computed, IReactionDisposer, Lambda, observable, reaction, runInAction } from "mobx";
 import { observer } from "mobx-react";
 import { baseKeymap } from "prosemirror-commands";
 import { history } from "prosemirror-history";
@@ -298,6 +298,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
         }
 
         this.pullFromGoogleDoc(this.checkState);
+        runInAction(() => DocumentDecorations.Instance.isAnimatingFetch = true);
 
         this._reactionDisposer = reaction(
             () => {
-- 
cgit v1.2.3-70-g09d2


From c0439996ec8b4858c48a7871120e19bb7c06c67d Mon Sep 17 00:00:00 2001
From: Sam Wilkins <samwilkins333@gmail.com>
Date: Tue, 20 Aug 2019 21:37:32 -0400
Subject: drag and drop google docs tweaks

---
 package.json                                       | 4 +---
 src/client/DocServer.ts                            | 1 -
 src/client/views/collections/CollectionSubView.tsx | 8 ++++----
 src/client/views/nodes/FormattedTextBox.tsx        | 1 +
 4 files changed, 6 insertions(+), 8 deletions(-)

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

diff --git a/package.json b/package.json
index e6a0a54b9..de1f3f6e6 100644
--- a/package.json
+++ b/package.json
@@ -63,7 +63,6 @@
         "@types/cookie-parser": "^1.4.1",
         "@types/cookie-session": "^2.0.36",
         "@types/d3-format": "^1.3.1",
-        "@types/diff": "^4.0.2",
         "@types/dotenv": "^6.1.1",
         "@types/express": "^4.16.1",
         "@types/express-flash": "0.0.0",
@@ -128,7 +127,6 @@
         "cookie-session": "^2.0.0-beta.3",
         "crypto-browserify": "^3.11.0",
         "d3-format": "^1.3.2",
-        "diff": "^4.0.1",
         "dotenv": "^8.0.0",
         "express": "^4.16.4",
         "express-flash": "0.0.2",
@@ -221,4 +219,4 @@
         "xoauth2": "^1.2.0",
         "youtube": "^0.1.0"
     }
-}
+}
\ No newline at end of file
diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts
index 56d9147ae..2cec1046b 100644
--- a/src/client/DocServer.ts
+++ b/src/client/DocServer.ts
@@ -5,7 +5,6 @@ import { Utils, emptyFunction } from '../Utils';
 import { SerializationHelper } from './util/SerializationHelper';
 import { RefField } from '../new_fields/RefField';
 import { Id, HandleUpdate } from '../new_fields/FieldSymbols';
-import { docs_v1 } from 'googleapis';
 
 /**
  * This class encapsulates the transfer and cross-client synchronization of
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 3deec22b5..5b50c545c 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -17,7 +17,7 @@ import { DragManager } from "../../util/DragManager";
 import { undoBatch, UndoManager } from "../../util/UndoManager";
 import { DocComponent } from "../DocComponent";
 import { FieldViewProps } from "../nodes/FieldView";
-import { FormattedTextBox, Blank } from "../nodes/FormattedTextBox";
+import { FormattedTextBox, GoogleRef } from "../nodes/FormattedTextBox";
 import { CollectionPDFView } from "./CollectionPDFView";
 import { CollectionVideoView } from "./CollectionVideoView";
 import { CollectionView } from "./CollectionView";
@@ -209,11 +209,11 @@ export function CollectionSubView<T>(schemaCtor: (doc: Doc) => T) {
             }
             let matches: RegExpExecArray | null;
             if ((matches = /(https:\/\/)?docs\.google\.com\/document\/d\/([^\\]+)\/edit/g.exec(text)) !== null) {
-                let newBox = Docs.Create.TextDocument({ ...options, width: 600, height: 400, title: "Fetching title from Google Docs..." });
+                let newBox = Docs.Create.TextDocument({ ...options, width: 400, height: 200, title: "Awaiting title from Google Docs..." });
                 let proto = newBox.proto!;
                 proto.autoHeight = true;
-                proto.googleDocId = matches[2];
-                proto.data = "Fetching contents from Google Docs...";
+                proto[GoogleRef] = matches[2];
+                proto.data = "Please select and then click on this document's pull button to load its contents from from Google Docs...";
                 proto.backgroundColor = "#eeeeff";
                 this.props.addDocument(newBox);
                 return;
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index d4cbb5116..2b01fb70a 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -434,6 +434,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
             delete dataDoc[GoogleRef];
         }
         DocumentDecorations.Instance.startPullOutcome(pullSuccess);
+        this.tryUpdateHeight();
     }
 
     checkState = (exportState: GoogleApiClientUtils.Docs.ReadResult, dataDoc: Doc) => {
-- 
cgit v1.2.3-70-g09d2


From 73bb0f572e261850583b698dd819d35a6fe768ec Mon Sep 17 00:00:00 2001
From: Sam Wilkins <samwilkins333@gmail.com>
Date: Tue, 20 Aug 2019 21:42:37 -0400
Subject: cleanup

---
 src/client/views/MainView.tsx                      | 2 +-
 src/client/views/collections/CollectionSubView.tsx | 2 +-
 src/client/views/nodes/FormattedTextBox.tsx        | 6 +++---
 3 files changed, 5 insertions(+), 5 deletions(-)

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

diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index e85374f6a..f28844009 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -15,7 +15,7 @@ import { listSpec } from '../../new_fields/Schema';
 import { BoolCast, Cast, FieldValue, StrCast } from '../../new_fields/Types';
 import { CurrentUserUtils } from '../../server/authentication/models/current_user_utils';
 import { RouteStore } from '../../server/RouteStore';
-import { emptyFunction, returnOne, returnTrue, Utils, returnEmptyString, PostToServer } from '../../Utils';
+import { emptyFunction, returnOne, returnTrue, Utils, returnEmptyString } from '../../Utils';
 import { DocServer } from '../DocServer';
 import { Docs } from '../documents/Documents';
 import { ClientUtils } from '../util/ClientUtils';
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 5b50c545c..99e5ab7b3 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -213,7 +213,7 @@ export function CollectionSubView<T>(schemaCtor: (doc: Doc) => T) {
                 let proto = newBox.proto!;
                 proto.autoHeight = true;
                 proto[GoogleRef] = matches[2];
-                proto.data = "Please select and then click on this document's pull button to load its contents from from Google Docs...";
+                proto.data = "Please select this document and then click on its pull button to load its contents from from Google Docs...";
                 proto.backgroundColor = "#eeeeff";
                 this.props.addDocument(newBox);
                 return;
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 2b01fb70a..606e8edb0 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -389,9 +389,9 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
                 };
             }
             let redo = async () => {
-                if (this._editorView && reference) {
-                    let data = Cast(this.dataDoc.data, RichTextField);
-                    let content = data ? data[ToPlainText]() : this._editorView.state.doc.textContent;
+                let data = Cast(this.dataDoc.data, RichTextField);
+                if (this._editorView && reference && data) {
+                    let content = data[ToPlainText]();
                     let response = await GoogleApiClientUtils.Docs.write({ reference, content, mode });
                     let pushSuccess = response !== undefined && !("errors" in response);
                     dataDoc.unchanged = pushSuccess;
-- 
cgit v1.2.3-70-g09d2


From 8fa3c03f1fae853e3c626e748aef76f9b7bbc875 Mon Sep 17 00:00:00 2001
From: kimdahey <claire_kim1@brown.edu>
Date: Tue, 20 Aug 2019 22:42:25 -0400
Subject: initial commit

---
 package.json                                |  2 +-
 src/client/util/DictationManager.ts         | 12 ++++++++++--
 src/client/views/nodes/FormattedTextBox.tsx | 20 ++++++++++++++++++++
 3 files changed, 31 insertions(+), 3 deletions(-)

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

diff --git a/package.json b/package.json
index de1f3f6e6..cd60b7b55 100644
--- a/package.json
+++ b/package.json
@@ -219,4 +219,4 @@
         "xoauth2": "^1.2.0",
         "youtube": "^0.1.0"
     }
-}
\ No newline at end of file
+}
diff --git a/src/client/util/DictationManager.ts b/src/client/util/DictationManager.ts
index 488a146bf..758482eae 100644
--- a/src/client/util/DictationManager.ts
+++ b/src/client/util/DictationManager.ts
@@ -301,11 +301,16 @@ export namespace DictationManager {
                 }
             }],
 
-            ["create bulleted note", {
+            ["new outline", {
                 action: (target: DocumentView) => {
                     let newBox = Docs.Create.TextDocument({ width: 400, height: 200, title: "My Outline" });
+                    newBox.autoHeight = true;
                     let proto = newBox.proto!;
-                    let proseMirrorState = '"{"doc":{"type":"doc","content":[{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"type":"text","text":""}]}]}]}]},"selection":{"type":"text","anchor":1,"head":1}}"';
+                    proto.page = -1;
+                    let prompt = "Press alt + r to start dictating here...";
+                    let head = 3;
+                    let anchor = head + prompt.length;
+                    let proseMirrorState = `{"doc":{"type":"doc","content":[{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"type":"text","text":"${prompt}"}]}]}]}]},"selection":{"type":"text","anchor":${anchor},"head":${head}}}`;
                     proto.data = new RichTextField(proseMirrorState);
                     proto.backgroundColor = "#eeffff";
                     target.props.addDocTab(newBox, proto, "onRight");
@@ -323,6 +328,9 @@ export namespace DictationManager {
                     let what = matches[2];
                     let dataDoc = Doc.GetProto(target.props.Document);
                     let fieldKey = "data";
+                    if (isNaN(count)) {
+                        return;
+                    }
                     for (let i = 0; i < count; i++) {
                         let created: Doc | undefined;
                         switch (what) {
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 606e8edb0..e460e3e50 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -35,6 +35,7 @@ import React = require("react");
 import { GoogleApiClientUtils, Pulls, Pushes } from '../../apis/google_docs/GoogleApiClientUtils';
 import { DocumentDecorations } from '../DocumentDecorations';
 import { MainOverlayTextBox } from '../MainOverlayTextBox';
+import { DictationManager } from '../../util/DictationManager';
 
 library.add(faEdit);
 library.add(faSmile, faTextHeight, faUpload);
@@ -265,7 +266,25 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
         }
     }
 
+    setCurrentBulletContent = (value: string) => {
+        if (this._editorView) {
+            this._editorView.state;
+        }
+    }
+
+    considerRecordingSession = (e: KeyboardEvent) => {
+        if (e.which === 82 && e.altKey) {
+            let continuous = { indefinite: true };
+            DictationManager.Controls.listen({
+                interimHandler: this.setCurrentBulletContent,
+                continuous
+            });
+        }
+    }
+
     componentDidMount() {
+        document.removeEventListener("keypress", this.considerRecordingSession);
+        document.addEventListener("keypress", this.considerRecordingSession);
         const config = {
             schema,
             inpRules, //these currently don't do anything, but could eventually be helpful
@@ -576,6 +595,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
     }
 
     componentWillUnmount() {
+        document.removeEventListener("keypress", this.considerRecordingSession);
         this._editorView && this._editorView.destroy();
         this._reactionDisposer && this._reactionDisposer();
         this._proxyReactionDisposer && this._proxyReactionDisposer();
-- 
cgit v1.2.3-70-g09d2


From d260d9abc13ae60c3206c3110f2d7f23ceeb2449 Mon Sep 17 00:00:00 2001
From: Sam Wilkins <samwilkins333@gmail.com>
Date: Wed, 21 Aug 2019 05:29:07 -0400
Subject: prosemirror bulleted list dictation integration

---
 src/client/util/DictationManager.ts         | 48 ++++++++++--------
 src/client/views/DocumentDecorations.tsx    |  3 +-
 src/client/views/nodes/FormattedTextBox.tsx | 76 ++++++++++++++++++++++++-----
 3 files changed, 93 insertions(+), 34 deletions(-)

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

diff --git a/src/client/util/DictationManager.ts b/src/client/util/DictationManager.ts
index 758482eae..781e5e465 100644
--- a/src/client/util/DictationManager.ts
+++ b/src/client/util/DictationManager.ts
@@ -45,7 +45,7 @@ export namespace DictationManager {
 
     export namespace Controls {
 
-        const infringe = "unable to process: dictation manager still involved in previous session";
+        export const Infringed = "unable to process: dictation manager still involved in previous session";
         const intraSession = ". ";
         const interSession = " ... ";
 
@@ -69,30 +69,32 @@ export namespace DictationManager {
             delimiters: DelimiterArgs;
             interimHandler: InterimResultHandler;
             tryExecute: boolean;
+            terminators: string[];
         }
 
         export const listen = async (options?: Partial<ListeningOptions>) => {
             let results: string | undefined;
-            let main = MainView.Instance;
+            // let main = MainView.Instance;
 
-            main.dictationOverlayVisible = true;
-            main.isListening = { interim: false };
+            // main.dictationOverlayVisible = true;
+            // main.isListening = { interim: false };
 
             try {
                 results = await listenImpl(options);
                 if (results) {
                     Utils.CopyText(results);
-                    main.isListening = false;
-                    let execute = options && options.tryExecute;
-                    main.dictatedPhrase = execute ? results.toLowerCase() : results;
-                    main.dictationSuccess = execute ? await DictationManager.Commands.execute(results) : true;
+                    // main.isListening = false;
+                    // let execute = options && options.tryExecute;
+                    // main.dictatedPhrase = execute ? results.toLowerCase() : results;
+                    // main.dictationSuccess = execute ? await DictationManager.Commands.execute(results) : true;
+                    options && options.tryExecute && await DictationManager.Commands.execute(results);
                 }
             } catch (e) {
-                main.isListening = false;
-                main.dictatedPhrase = results = `dictation error: ${"error" in e ? e.error : "unknown error"}`;
-                main.dictationSuccess = false;
+                // main.isListening = false;
+                // main.dictatedPhrase = results = `dictation error: ${"error" in e ? e.error : "unknown error"}`;
+                // main.dictationSuccess = false;
             } finally {
-                main.initiateDictationFade();
+                // main.initiateDictationFade();
             }
 
             return results;
@@ -100,7 +102,7 @@ export namespace DictationManager {
 
         const listenImpl = (options?: Partial<ListeningOptions>) => {
             if (isListening) {
-                return infringe;
+                return Infringed;
             }
             isListening = true;
 
@@ -128,6 +130,12 @@ export namespace DictationManager {
 
                 recognizer.onresult = (e: SpeechRecognitionEvent) => {
                     current = synthesize(e, intra);
+                    let matchedTerminator: string | undefined;
+                    if (options && options.terminators && (matchedTerminator = options.terminators.find(end => current ? current.trim().toLowerCase().endsWith(end.toLowerCase()) : false))) {
+                        current = matchedTerminator;
+                        recognizer.abort();
+                        return complete();
+                    }
                     handler && handler(current);
                     isManuallyStopped && complete();
                 };
@@ -163,13 +171,13 @@ export namespace DictationManager {
             }
             isManuallyStopped = true;
             salvageSession ? recognizer.stop() : recognizer.abort();
-            let main = MainView.Instance;
-            if (main.dictationOverlayVisible) {
-                main.cancelDictationFade();
-                main.dictationOverlayVisible = false;
-                main.dictationSuccess = undefined;
-                setTimeout(() => main.dictatedPhrase = placeholder, 500);
-            }
+            // let main = MainView.Instance;
+            // if (main.dictationOverlayVisible) {
+            // main.cancelDictationFade();
+            // main.dictationOverlayVisible = false;
+            // main.dictationSuccess = undefined;
+            // setTimeout(() => main.dictatedPhrase = placeholder, 500);
+            // }
         };
 
         const synthesize = (e: SpeechRecognitionEvent, delimiter?: string) => {
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 891fd7847..cc8e57af9 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -730,7 +730,8 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
                     onPointerEnter={e => e.ctrlKey && runInAction(() => this.openHover = true)}
                     onPointerLeave={() => runInAction(() => this.openHover = false)}
                     onClick={e => {
-                        if (e.ctrlKey) {
+                        if (e.altKey) {
+                            e.preventDefault();
                             window.open(`https://docs.google.com/document/d/${dataDoc[GoogleRef]}/edit`);
                         } else {
                             this.clearPullColor();
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index e460e3e50..222ebed8f 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -6,7 +6,7 @@ import { baseKeymap } from "prosemirror-commands";
 import { history } from "prosemirror-history";
 import { keymap } from "prosemirror-keymap";
 import { Fragment, Node, Node as ProsNode, NodeType, Slice } from "prosemirror-model";
-import { EditorState, Plugin, Transaction } from "prosemirror-state";
+import { EditorState, Plugin, Transaction, TextSelection } from "prosemirror-state";
 import { EditorView } from "prosemirror-view";
 import { DateField } from '../../../new_fields/DateField';
 import { Doc, DocListCast, Opt, WidthSym } from "../../../new_fields/Doc";
@@ -36,6 +36,7 @@ import { GoogleApiClientUtils, Pulls, Pushes } from '../../apis/google_docs/Goog
 import { DocumentDecorations } from '../DocumentDecorations';
 import { MainOverlayTextBox } from '../MainOverlayTextBox';
 import { DictationManager } from '../../util/DictationManager';
+import { ReplaceStep } from 'prosemirror-transform';
 
 library.add(faEdit);
 library.add(faSmile, faTextHeight, faUpload);
@@ -181,6 +182,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
                 const marks = tx.storedMarks;
                 if (marks) { FormattedTextBox._toolTipTextMenu.mark_key_pressed(marks); }
             }
+
             this._applyingChange = true;
             const fieldkey = "preview";
             if (this.extensionDoc) this.extensionDoc.text = state.doc.textBetween(0, state.doc.content.size, "\n\n");
@@ -268,23 +270,70 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
 
     setCurrentBulletContent = (value: string) => {
         if (this._editorView) {
-            this._editorView.state;
+            // let next = value.endsWith("bullet");
+            // if (next) {
+            //     value = value.split("bullet")[0];
+            // }
+            let state = this._editorView.state;
+            let from = state.selection.from;
+            let to = state.selection.to;
+            this._editorView.dispatch(state.tr.insertText(value, from, to));
+            state = this._editorView.state;
+            let updated = TextSelection.create(state.doc, from, from + value.length);
+            this._editorView.dispatch(state.tr.setSelection(updated));
+            // if (next) {
+            //     this.nextBullet(this._editorView.state.selection.to);
+            // }
         }
     }
 
-    considerRecordingSession = (e: KeyboardEvent) => {
-        if (e.which === 82 && e.altKey) {
-            let continuous = { indefinite: true };
-            DictationManager.Controls.listen({
-                interimHandler: this.setCurrentBulletContent,
-                continuous
-            });
+    nextBullet = (pos: number) => {
+        if (this._editorView) {
+            // DictationManager.Controls.stop(false);
+            let frag = Fragment.fromArray(this.newListItems(2));
+            let slice = new Slice(frag, 2, 2);
+            let state = this._editorView.state;
+            this._editorView.dispatch(state.tr.step(new ReplaceStep(pos, pos, slice)));
+            pos += 4;
+            state = this._editorView.state;
+            this._editorView.dispatch(state.tr.setSelection(TextSelection.create(this._editorView.state.doc, pos, pos)));
+            // this.recordSession();
+        }
+    }
+
+    private newListItems = (count: number) => {
+        let listItems: any[] = [];
+        for (let i = 0; i < count; i++) {
+            listItems.push(schema.nodes.list_item.create(null, schema.nodes.paragraph.create(null)));
         }
+        return listItems;
+    }
+
+    recordSession = async () => {
+        let completedCue = "end session";
+        let results = await DictationManager.Controls.listen({
+            interimHandler: this.setCurrentBulletContent,
+            continuous: { indefinite: false },
+            terminators: [completedCue, "bullet", "next"]
+        });
+        if (results && [DictationManager.Controls.Infringed, completedCue].includes(results)) {
+            DictationManager.Controls.stop();
+            return;
+        }
+        this.nextBullet(this._editorView!.state.selection.to);
+        setTimeout(this.recordSession, 2000);
+    }
+
+    recordKeyHandler = (e: KeyboardEvent) => {
+        if (this.props.Document !== SelectionManager.SelectedDocuments()[0].props.Document) {
+            return;
+        }
+        e.stopPropagation();
+        e.preventDefault();
+        e.which === 174 && e.altKey && this.recordSession();
     }
 
     componentDidMount() {
-        document.removeEventListener("keypress", this.considerRecordingSession);
-        document.addEventListener("keypress", this.considerRecordingSession);
         const config = {
             schema,
             inpRules, //these currently don't do anything, but could eventually be helpful
@@ -335,7 +384,6 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
                         updatedState.selection = { type: "text", anchor: end, head: end };
                         this._editorView.updateState(EditorState.fromJSON(config, updatedState));
                     }
-                    this.tryUpdateHeight();
                 }
             }
         );
@@ -595,7 +643,6 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
     }
 
     componentWillUnmount() {
-        document.removeEventListener("keypress", this.considerRecordingSession);
         this._editorView && this._editorView.destroy();
         this._reactionDisposer && this._reactionDisposer();
         this._proxyReactionDisposer && this._proxyReactionDisposer();
@@ -678,6 +725,8 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
 
     @action
     onFocused = (e: React.FocusEvent): void => {
+        document.removeEventListener("keypress", this.recordKeyHandler);
+        document.addEventListener("keypress", this.recordKeyHandler);
         if (!this.props.isOverlay) {
             FormattedTextBox.InputBoxOverlay = this;
         } else {
@@ -727,6 +776,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
         });
     }
     onBlur = (e: any) => {
+        document.removeEventListener("keypress", this.recordKeyHandler);
         if (this._undoTyping) {
             this._undoTyping.end();
             this._undoTyping = undefined;
-- 
cgit v1.2.3-70-g09d2


From 654db73e0615e77f7206128b6e5524553d653c66 Mon Sep 17 00:00:00 2001
From: Sam Wilkins <samwilkins333@gmail.com>
Date: Wed, 21 Aug 2019 05:30:39 -0400
Subject: cleanup

---
 src/client/views/nodes/FormattedTextBox.tsx | 57 ++++++++++++-----------------
 1 file changed, 24 insertions(+), 33 deletions(-)

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

diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 222ebed8f..a2ea12ac5 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -268,12 +268,32 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
         }
     }
 
+    recordKeyHandler = (e: KeyboardEvent) => {
+        if (this.props.Document !== SelectionManager.SelectedDocuments()[0].props.Document) {
+            return;
+        }
+        e.stopPropagation();
+        e.preventDefault();
+        e.which === 174 && e.altKey && this.recordBullet();
+    }
+
+    recordBullet = async () => {
+        let completedCue = "end session";
+        let results = await DictationManager.Controls.listen({
+            interimHandler: this.setCurrentBulletContent,
+            continuous: { indefinite: false },
+            terminators: [completedCue, "bullet", "next"]
+        });
+        if (results && [DictationManager.Controls.Infringed, completedCue].includes(results)) {
+            DictationManager.Controls.stop();
+            return;
+        }
+        this.nextBullet(this._editorView!.state.selection.to);
+        setTimeout(this.recordBullet, 2000);
+    }
+
     setCurrentBulletContent = (value: string) => {
         if (this._editorView) {
-            // let next = value.endsWith("bullet");
-            // if (next) {
-            //     value = value.split("bullet")[0];
-            // }
             let state = this._editorView.state;
             let from = state.selection.from;
             let to = state.selection.to;
@@ -281,15 +301,11 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
             state = this._editorView.state;
             let updated = TextSelection.create(state.doc, from, from + value.length);
             this._editorView.dispatch(state.tr.setSelection(updated));
-            // if (next) {
-            //     this.nextBullet(this._editorView.state.selection.to);
-            // }
         }
     }
 
     nextBullet = (pos: number) => {
         if (this._editorView) {
-            // DictationManager.Controls.stop(false);
             let frag = Fragment.fromArray(this.newListItems(2));
             let slice = new Slice(frag, 2, 2);
             let state = this._editorView.state;
@@ -297,7 +313,6 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
             pos += 4;
             state = this._editorView.state;
             this._editorView.dispatch(state.tr.setSelection(TextSelection.create(this._editorView.state.doc, pos, pos)));
-            // this.recordSession();
         }
     }
 
@@ -309,30 +324,6 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
         return listItems;
     }
 
-    recordSession = async () => {
-        let completedCue = "end session";
-        let results = await DictationManager.Controls.listen({
-            interimHandler: this.setCurrentBulletContent,
-            continuous: { indefinite: false },
-            terminators: [completedCue, "bullet", "next"]
-        });
-        if (results && [DictationManager.Controls.Infringed, completedCue].includes(results)) {
-            DictationManager.Controls.stop();
-            return;
-        }
-        this.nextBullet(this._editorView!.state.selection.to);
-        setTimeout(this.recordSession, 2000);
-    }
-
-    recordKeyHandler = (e: KeyboardEvent) => {
-        if (this.props.Document !== SelectionManager.SelectedDocuments()[0].props.Document) {
-            return;
-        }
-        e.stopPropagation();
-        e.preventDefault();
-        e.which === 174 && e.altKey && this.recordSession();
-    }
-
     componentDidMount() {
         const config = {
             schema,
-- 
cgit v1.2.3-70-g09d2


From 186cf33322b6c96386c6e9fdb823025d09c5caeb Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Wed, 21 Aug 2019 11:35:18 -0400
Subject: extended treeview functionality - better indenting, state management,
 drag dropping.

---
 src/client/views/EditableView.tsx                  | 28 +++++---
 .../views/collections/CollectionTreeView.tsx       | 83 +++++++++++++---------
 src/client/views/nodes/FormattedTextBox.tsx        |  1 -
 .../authentication/models/current_user_utils.ts    |  5 +-
 4 files changed, 75 insertions(+), 42 deletions(-)

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

diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx
index c3612fee9..dd5395802 100644
--- a/src/client/views/EditableView.tsx
+++ b/src/client/views/EditableView.tsx
@@ -3,6 +3,7 @@ import { observer } from 'mobx-react';
 import { observable, action, trace } from 'mobx';
 import "./EditableView.scss";
 import * as Autosuggest from 'react-autosuggest';
+import { undoBatch } from '../util/UndoManager';
 
 export interface EditableProps {
     /**
@@ -70,14 +71,12 @@ export class EditableView extends React.Component<EditableProps> {
     onKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
         if (e.key === "Tab") {
             e.stopPropagation();
+            this.finalizeEdit(e.currentTarget.value, e.shiftKey);
             this.props.OnTab && this.props.OnTab();
         } else if (e.key === "Enter") {
             e.stopPropagation();
             if (!e.ctrlKey) {
-                if (this.props.SetValue(e.currentTarget.value, e.shiftKey)) {
-                    this._editing = false;
-                    this.props.isEditingCallback && this.props.isEditingCallback(false);
-                }
+                this.finalizeEdit(e.currentTarget.value, e.shiftKey);
             } else if (this.props.OnFillDown) {
                 this.props.OnFillDown(e.currentTarget.value);
                 this._editing = false;
@@ -100,6 +99,14 @@ export class EditableView extends React.Component<EditableProps> {
         e.stopPropagation();
     }
 
+    @action
+    private finalizeEdit(value: string, shiftDown: boolean) {
+        if (this.props.SetValue(value, shiftDown)) {
+            this._editing = false;
+            this.props.isEditingCallback && this.props.isEditingCallback(false);
+        }
+    }
+
     stopPropagation(e: React.SyntheticEvent) {
         e.stopPropagation();
     }
@@ -118,7 +125,7 @@ export class EditableView extends React.Component<EditableProps> {
                         className: "editableView-input",
                         onKeyDown: this.onKeyDown,
                         autoFocus: true,
-                        onBlur: action(() => this._editing = false),
+                        onBlur: e => this.finalizeEdit(e.currentTarget.value, false),
                         onPointerDown: this.stopPropagation,
                         onClick: this.stopPropagation,
                         onPointerUp: this.stopPropagation,
@@ -126,9 +133,14 @@ export class EditableView extends React.Component<EditableProps> {
                         onChange: this.props.autosuggestProps.onChange
                     }}
                 />
-                : <input className="editableView-input" defaultValue={this.props.GetValue()} onKeyDown={this.onKeyDown} autoFocus
-                    onBlur={action(() => { this._editing = false; this.props.isEditingCallback && this.props.isEditingCallback(false); })} onPointerDown={this.stopPropagation} onClick={this.stopPropagation} onPointerUp={this.stopPropagation}
-                    style={{ display: this.props.display, fontSize: this.props.fontSize }} />;
+                : <input className="editableView-input"
+                    defaultValue={this.props.GetValue()}
+                    onKeyDown={this.onKeyDown}
+                    autoFocus={true}
+                    onBlur={e => this.finalizeEdit(e.currentTarget.value, false)}
+                    onPointerDown={this.stopPropagation} onClick={this.stopPropagation} onPointerUp={this.stopPropagation}
+                    style={{ display: this.props.display, fontSize: this.props.fontSize }}
+                />;
         } else {
             if (this.props.autosuggestProps) this.props.autosuggestProps.resetValue();
             return (
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index ebd385743..e1eb9e1a5 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -49,6 +49,8 @@ export interface TreeViewProps {
     treeViewId: string;
     parentKey: string;
     active: () => boolean;
+    showHeaderFields: () => boolean;
+    preventTreeViewOpen: boolean;
 }
 
 library.add(faTrashAlt);
@@ -65,7 +67,12 @@ library.add(faArrowsAltH);
 library.add(faPlus, faMinus);
 @observer
 /**
- * Component that takes in a document prop and a boolean whether it's collapsed or not.
+ * Renders a treeView of a collection of documents
+ * 
+ * special fields:
+ * treeViewOpen : flag denoting whether the documents sub-tree (contents) is visible or hidden
+ * preventTreeViewOpen : ignores the treeViewOpen flag (for allowing a view to not be slaved to other views of the document)
+ * treeViewExpandedView : name of field whose contents are being displayed as the document's subtree
  */
 class TreeView extends React.Component<TreeViewProps> {
     static loadId = "";
@@ -73,7 +80,9 @@ class TreeView extends React.Component<TreeViewProps> {
     private _treedropDisposer?: DragManager.DragDropDisposer;
     private _dref = React.createRef<HTMLDivElement>();
     get defaultExpandedView() { return this.childDocs ? this.fieldKey : "fields"; }
-    @observable _collapsed: boolean = true;
+    @observable _overrideTreeViewOpen = false; // override of the treeViewOpen field allowing the display state to be independent of the document's state
+    @computed get treeViewOpen() { return (BoolCast(this.props.document.treeViewOpen) && !this.props.preventTreeViewOpen) || this._overrideTreeViewOpen; }
+    set treeViewOpen(c: boolean) { if (this.props.preventTreeViewOpen) this._overrideTreeViewOpen = c; else this.props.document.treeViewOpen = c; }
     @computed get treeViewExpandedView() { return StrCast(this.props.document.treeViewExpandedView, this.defaultExpandedView); }
     @computed get MAX_EMBED_HEIGHT() { return NumCast(this.props.document.maxEmbedHeight, 300); }
     @computed get dataDoc() { return this.resolvedDataDoc ? this.resolvedDataDoc : this.props.document; }
@@ -146,7 +155,7 @@ class TreeView extends React.Component<TreeViewProps> {
         let rect = this._header!.current!.getBoundingClientRect();
         let bounds = this.props.ScreenToLocalTransform().transformPoint(rect.left, rect.top + rect.height / 2);
         let before = x[1] < bounds[1];
-        let inside = x[0] > bounds[0] + 75 || (!before && !this._collapsed);
+        let inside = x[0] > bounds[0] + 75 || (!before && this.treeViewOpen);
         this._header!.current!.className = "treeViewItem-header";
         if (inside) this._header!.current!.className += " treeViewItem-header-inside";
         else if (before) this._header!.current!.className += " treeViewItem-header-above";
@@ -163,15 +172,15 @@ class TreeView extends React.Component<TreeViewProps> {
         fontStyle={style}
         fontSize={12}
         GetValue={() => StrCast(this.props.document[key])}
-        SetValue={(value: string) => (Doc.GetProto(this.dataDoc)[key] = value) ? true : true}
-        OnFillDown={(value: string) => {
+        SetValue={undoBatch((value: string) => (Doc.GetProto(this.dataDoc)[key] = value) ? true : true)}
+        OnFillDown={undoBatch((value: string) => {
             Doc.GetProto(this.dataDoc)[key] = value;
             let doc = this.props.document.detailedLayout instanceof Doc ? Doc.ApplyTemplate(Doc.GetProto(this.props.document.detailedLayout)) : undefined;
             if (!doc) doc = Docs.Create.FreeformDocument([], { title: "", x: 0, y: 0, width: 100, height: 25, templates: new List<string>([Templates.Title.Layout]) });
             TreeView.loadId = doc[Id];
             return this.props.addDocument(doc);
-        }}
-        OnTab={() => this.props.indentDocument && this.props.indentDocument()}
+        })}
+        OnTab={() => { TreeView.loadId = ""; this.props.indentDocument && this.props.indentDocument(); }}
     />)
 
     onWorkspaceContextMenu = (e: React.MouseEvent): void => {
@@ -200,7 +209,7 @@ class TreeView extends React.Component<TreeViewProps> {
         let rect = this._header!.current!.getBoundingClientRect();
         let bounds = this.props.ScreenToLocalTransform().transformPoint(rect.left, rect.top + rect.height / 2);
         let before = x[1] < bounds[1];
-        let inside = x[0] > bounds[0] + 75 || (!before && !this._collapsed);
+        let inside = x[0] > bounds[0] + 75 || (!before && this.treeViewOpen);
         if (de.data instanceof DragManager.LinkDragData) {
             let sourceDoc = de.data.linkSourceDocument;
             let destDoc = this.props.document;
@@ -256,14 +265,14 @@ class TreeView extends React.Component<TreeViewProps> {
         let rows: JSX.Element[] = [];
         for (let key of Object.keys(ids).slice().sort()) {
             let contents = doc[key];
-            let contentElement: JSX.Element[] | JSX.Element = [];
+            let contentElement: (JSX.Element | null)[] | JSX.Element = [];
 
             if (contents instanceof Doc || Cast(contents, listSpec(Doc))) {
                 let remDoc = (doc: Doc) => this.remove(doc, key);
-                let addDoc = (doc: Doc, addBefore?: Doc, before?: boolean) => Doc.AddDocToList(this.dataDoc, key, doc, addBefore, before, !BoolCast(this.props.document.stackingHeadersSortDescending));
+                let addDoc = (doc: Doc, addBefore?: Doc, before?: boolean) => Doc.AddDocToList(this.dataDoc, key, doc, addBefore, before, !BoolCast(this.props.document.stackingHeadersSortDescending, true));
                 contentElement = TreeView.GetChildElements(contents instanceof Doc ? [contents] :
                     DocListCast(contents), this.props.treeViewId, doc, undefined, key, addDoc, remDoc, this.move,
-                    this.props.dropAction, this.props.addDocTab, this.props.pinToPres, this.props.ScreenToLocalTransform, this.props.outerXf, this.props.active, this.props.panelWidth, this.props.renderDepth);
+                    this.props.dropAction, this.props.addDocTab, this.props.pinToPres, this.props.ScreenToLocalTransform, this.props.outerXf, this.props.active, this.props.panelWidth, this.props.renderDepth, this.props.showHeaderFields, this.props.preventTreeViewOpen);
             } else {
                 contentElement = <EditableView
                     key="editableView"
@@ -288,14 +297,14 @@ class TreeView extends React.Component<TreeViewProps> {
         const expandKey = this.treeViewExpandedView === this.fieldKey ? this.fieldKey : this.treeViewExpandedView === "links" ? "links" : undefined;
         if (expandKey !== undefined) {
             let remDoc = (doc: Doc) => this.remove(doc, expandKey);
-            let addDoc = (doc: Doc, addBefore?: Doc, before?: boolean) => Doc.AddDocToList(this.dataDoc, expandKey, doc, addBefore, before, !BoolCast(this.props.document.stackingHeadersSortDescending));
+            let addDoc = (doc: Doc, addBefore?: Doc, before?: boolean) => Doc.AddDocToList(this.dataDoc, expandKey, doc, addBefore, before, !BoolCast(this.props.document.stackingHeadersSortDescending, true));
             let docs = expandKey === "links" ? this.childLinks : this.childDocs;
             return <ul key={expandKey + "more"}>
                 {!docs ? (null) :
                     TreeView.GetChildElements(docs as Doc[], this.props.treeViewId, this.props.document.layout as Doc,
                         this.resolvedDataDoc, expandKey, addDoc, remDoc, this.move,
                         this.props.dropAction, this.props.addDocTab, this.props.pinToPres, this.props.ScreenToLocalTransform,
-                        this.props.outerXf, this.props.active, this.props.panelWidth, this.props.renderDepth)}
+                        this.props.outerXf, this.props.active, this.props.panelWidth, this.props.renderDepth, this.props.showHeaderFields, this.props.preventTreeViewOpen)}
             </ul >;
         } else if (this.treeViewExpandedView === "fields") {
             return <ul><div ref={this._dref} style={{ display: "inline-block" }} key={this.props.document[Id] + this.props.document.title}>
@@ -329,8 +338,8 @@ class TreeView extends React.Component<TreeViewProps> {
 
     @computed
     get renderBullet() {
-        return <div className="bullet" onClick={action(() => this._collapsed = !this._collapsed)} style={{ color: StrCast(this.props.document.color, "black"), opacity: 0.4 }}>
-            {<FontAwesomeIcon icon={this._collapsed ? (this.childDocs ? "caret-square-right" : "caret-right") : (this.childDocs ? "caret-square-down" : "caret-down")} />}
+        return <div className="bullet" onClick={action(() => this.treeViewOpen = !this.treeViewOpen)} style={{ color: StrCast(this.props.document.color, "black"), opacity: 0.4 }}>
+            {<FontAwesomeIcon icon={!this.treeViewOpen ? (this.childDocs ? "caret-square-right" : "caret-right") : (this.childDocs ? "caret-square-down" : "caret-down")} />}
         </div>;
     }
     /**
@@ -344,13 +353,13 @@ class TreeView extends React.Component<TreeViewProps> {
         let headerElements = (
             <span className="collectionTreeView-keyHeader" key={this.treeViewExpandedView}
                 onPointerDown={action(() => {
-                    if (!this._collapsed) {
+                    if (this.treeViewOpen) {
                         this.props.document.treeViewExpandedView = this.treeViewExpandedView === this.fieldKey ? "fields" :
                             this.treeViewExpandedView === "fields" && this.props.document.layout ? "layout" :
                                 this.treeViewExpandedView === "layout" && this.props.document.links ? "links" :
                                     this.childDocs ? this.fieldKey : "fields";
                     }
-                    this._collapsed = false;
+                    this.treeViewOpen = true;
                 })}>
                 {this.treeViewExpandedView}
             </span>);
@@ -368,7 +377,7 @@ class TreeView extends React.Component<TreeViewProps> {
                 }} >
                 {this.editableView("title")}
             </div >
-            {headerElements}
+            {this.props.showHeaderFields() ? headerElements : (null)}
             {openRight}
         </>;
     }
@@ -381,13 +390,13 @@ class TreeView extends React.Component<TreeViewProps> {
                     {this.renderTitle}
                 </div>
                 <div className="treeViewItem-border">
-                    {this._collapsed ? (null) : this.renderContent}
+                    {!this.treeViewOpen ? (null) : this.renderContent}
                 </div>
             </li>
         </div>;
     }
     public static GetChildElements(
-        docs: Doc[],
+        docList: Doc[],
         treeViewId: string,
         containingCollection: Doc,
         dataDoc: Doc | undefined,
@@ -402,8 +411,11 @@ class TreeView extends React.Component<TreeViewProps> {
         outerXf: () => { translateX: number, translateY: number },
         active: () => boolean,
         panelWidth: () => number,
-        renderDepth: number
+        renderDepth: number,
+        showHeaderFields: () => boolean,
+        preventTreeViewOpen: boolean
     ) {
+        let docs = docList.filter(child => !child.excludeFromLibrary);
         let viewSpecScript = Cast(containingCollection.viewSpecScript, ScriptField);
         if (viewSpecScript) {
             let script = viewSpecScript.script;
@@ -418,7 +430,7 @@ class TreeView extends React.Component<TreeViewProps> {
             });
         }
 
-        let descending = BoolCast(containingCollection.stackingHeadersSortDescending);
+        let descending = BoolCast(containingCollection.stackingHeadersSortDescending, true);
         docs.slice().sort(function (a, b): 1 | -1 {
             let descA = descending ? b : a;
             let descB = descending ? a : b;
@@ -448,11 +460,14 @@ class TreeView extends React.Component<TreeViewProps> {
             }
 
             let indent = i === 0 ? undefined : () => {
-                if (StrCast(docs[i - 1].layout).indexOf("CollectionView") !== -1) {
+                if (StrCast(docs[i - 1].layout).indexOf("fieldKey") !== -1) {
                     let fieldKeysub = StrCast(docs[i - 1].layout).split("fieldKey")[1];
                     let fieldKey = fieldKeysub.split("\"")[1];
-                    Doc.AddDocToList(docs[i - 1], fieldKey, child);
-                    remove(child);
+                    if (fieldKey && Cast(docs[i - 1][fieldKey], listSpec(Doc)) !== undefined) {
+                        Doc.AddDocToList(docs[i - 1], fieldKey, child);
+                        docs[i - 1].treeViewOpen = true;
+                        remove(child);
+                    }
                 }
             };
             let addDocument = (doc: Doc, relativeTo?: Doc, before?: boolean) => {
@@ -481,7 +496,9 @@ class TreeView extends React.Component<TreeViewProps> {
                 ScreenToLocalTransform={screenToLocalXf}
                 outerXf={outerXf}
                 parentKey={key}
-                active={active} />;
+                active={active}
+                showHeaderFields={showHeaderFields}
+                preventTreeViewOpen={preventTreeViewOpen} />;
         });
     }
 }
@@ -561,7 +578,7 @@ export class CollectionTreeView extends CollectionSubView(Document) {
     render() {
         Doc.UpdateDocumentExtensionForField(this.props.DataDoc ? this.props.DataDoc : this.props.Document, this.props.fieldKey);
         let dropAction = StrCast(this.props.Document.dropAction) as dropActionType;
-        let addDoc = (doc: Doc, relativeTo?: Doc, before?: boolean) => Doc.AddDocToList(this.props.Document, this.props.fieldKey, doc, relativeTo, before, !BoolCast(this.props.Document.stackingHeadersSortDescending));
+        let addDoc = (doc: Doc, relativeTo?: Doc, before?: boolean) => Doc.AddDocToList(this.props.Document, this.props.fieldKey, doc, relativeTo, before, false, false, !BoolCast(this.props.Document.stackingHeadersSortDescending, true));
         let moveDoc = (d: Doc, target: Doc, addDoc: (doc: Doc) => boolean) => this.props.moveDocument(d, target, addDoc);
         return !this.childDocs ? (null) : (
             <div id="body" className="collectionTreeView-dropTarget"
@@ -575,20 +592,22 @@ export class CollectionTreeView extends CollectionSubView(Document) {
                     display={"block"}
                     height={72}
                     GetValue={() => StrCast(this.resolvedDataDoc.title)}
-                    SetValue={(value: string) => (Doc.GetProto(this.resolvedDataDoc).title = value) ? true : true}
-                    OnFillDown={(value: string) => {
+                    SetValue={undoBatch((value: string) => (Doc.GetProto(this.resolvedDataDoc).title = value) ? true : true)}
+                    OnFillDown={undoBatch((value: string) => {
                         Doc.GetProto(this.props.Document).title = value;
                         let doc = this.props.Document.detailedLayout instanceof Doc ? Doc.ApplyTemplate(Doc.GetProto(this.props.Document.detailedLayout)) : undefined;
                         if (!doc) doc = Docs.Create.FreeformDocument([], { title: "", x: 0, y: 0, width: 100, height: 25, templates: new List<string>([Templates.Title.Layout]) });
                         TreeView.loadId = doc[Id];
-                        Doc.AddDocToList(this.props.Document, this.props.fieldKey, doc, this.childDocs.length ? this.childDocs[0] : undefined, true, !BoolCast(this.props.Document.stackingHeadersSortDescending));
-                    }} />
+                        Doc.AddDocToList(this.props.Document, this.props.fieldKey, doc, this.childDocs.length ? this.childDocs[0] : undefined, true, false, false, !BoolCast(this.props.Document.stackingHeadersSortDescending, true));
+                    })} />
                 {this.props.Document.workspaceLibrary ? this.renderNotifsButton : (null)}
                 {this.props.Document.allowClear ? this.renderClearButton : (null)}
                 <ul className="no-indent" style={{ width: "max-content" }} >
                     {
                         TreeView.GetChildElements(this.childDocs, this.props.Document[Id], this.props.Document, this.props.DataDoc, this.props.fieldKey, addDoc, this.remove,
-                            moveDoc, dropAction, this.props.addDocTab, this.props.pinToPres, this.props.ScreenToLocalTransform, this.outerXf, this.props.active, this.props.PanelWidth, this.props.renderDepth)
+                            moveDoc, dropAction, this.props.addDocTab, this.props.pinToPres, this.props.ScreenToLocalTransform,
+                            this.outerXf, this.props.active, this.props.PanelWidth, this.props.renderDepth, () => this.props.Document.chromeStatus !== "disabled",
+                            BoolCast(this.props.Document.preventTreeViewOpen))
                     }
                 </ul>
             </div >
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 606e8edb0..3f3360eff 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -736,7 +736,6 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
     @action
     tryUpdateHeight() {
         if (this.props.Document.autoHeight && this._ref.current!.scrollHeight !== 0) {
-            console.log("DT = " + this.props.Document.title + " " + this._ref.current!.clientHeight + " " + this._ref.current!.scrollHeight + " " + this._ref.current!.textContent);
             let xf = this._ref.current!.getBoundingClientRect();
             let scrBounds = this.props.ScreenToLocalTransform().transformBounds(0, 0, xf.width, this._ref.current!.textContent === "" ? 35 : this._ref.current!.scrollHeight);
             let nh = this.props.Document.isTemplate ? 0 : NumCast(this.dataDoc.nativeHeight, 0);
diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts
index 508655605..aa3da0034 100644
--- a/src/server/authentication/models/current_user_utils.ts
+++ b/src/server/authentication/models/current_user_utils.ts
@@ -10,7 +10,7 @@ import { CollectionView } from "../../../client/views/collections/CollectionView
 import { Doc } from "../../../new_fields/Doc";
 import { List } from "../../../new_fields/List";
 import { listSpec } from "../../../new_fields/Schema";
-import { Cast, StrCast } from "../../../new_fields/Types";
+import { Cast, StrCast, PromiseValue } from "../../../new_fields/Types";
 import { Utils } from "../../../Utils";
 import { RouteStore } from "../../RouteStore";
 
@@ -49,12 +49,14 @@ export class CurrentUserUtils {
             workspaces.boxShadow = "0 0";
             doc.workspaces = workspaces;
         }
+        PromiseValue(Cast(doc.workspaces, Doc)).then(workspaces => workspaces && (workspaces.preventTreeViewOpen = true));
         if (doc.recentlyClosed === undefined) {
             const recentlyClosed = Docs.Create.TreeDocument([], { title: "Recently Closed", height: 75 });
             recentlyClosed.excludeFromLibrary = true;
             recentlyClosed.boxShadow = "0 0";
             doc.recentlyClosed = recentlyClosed;
         }
+        PromiseValue(Cast(doc.recentlyClosed, Doc)).then(recent => recent && (recent.preventTreeViewOpen = true));
         if (doc.curPresentation === undefined) {
             const curPresentation = Docs.Create.PresDocument(new List<Doc>(), { title: "Presentation" });
             curPresentation.excludeFromLibrary = true;
@@ -73,6 +75,7 @@ export class CurrentUserUtils {
         }
         StrCast(doc.title).indexOf("@") !== -1 && (doc.title = StrCast(doc.title).split("@")[0] + "'s Library");
         doc.width = 100;
+        doc.preventTreeViewOpen = true;
     }
 
     public static loadCurrentUser() {
-- 
cgit v1.2.3-70-g09d2


From 7153da56f27226cc6f92848b4548032bd5e32170 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Wed, 21 Aug 2019 12:58:34 -0400
Subject: tweaks

---
 src/client/views/nodes/FormattedTextBox.tsx | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

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

diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index a2ea12ac5..f2ca0715a 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -274,7 +274,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
         }
         e.stopPropagation();
         e.preventDefault();
-        e.which === 174 && e.altKey && this.recordBullet();
+        e.key === "R" && this.recordBullet();
     }
 
     recordBullet = async () => {
@@ -282,7 +282,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
         let results = await DictationManager.Controls.listen({
             interimHandler: this.setCurrentBulletContent,
             continuous: { indefinite: false },
-            terminators: [completedCue, "bullet", "next"]
+            // terminators: [completedCue, "bullet", "next"]
         });
         if (results && [DictationManager.Controls.Infringed, completedCue].includes(results)) {
             DictationManager.Controls.stop();
-- 
cgit v1.2.3-70-g09d2


From 3535bd703cfdb4872ff6ff0c41d17e39ad1c8e45 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Wed, 21 Aug 2019 13:17:50 -0400
Subject: fixed updating size of textboxes

---
 src/client/views/nodes/FormattedTextBox.tsx | 15 ++++++++-------
 1 file changed, 8 insertions(+), 7 deletions(-)

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

diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 0c39a57ff..505257e9c 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -272,9 +272,11 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
         if (this.props.Document !== SelectionManager.SelectedDocuments()[0].props.Document) {
             return;
         }
-        e.stopPropagation();
-        e.preventDefault();
-        e.key === "R" && this.recordBullet();
+        if (e.key === "R" && e.altKey) {
+            e.stopPropagation();
+            e.preventDefault();
+            this.recordBullet();
+        }
     }
 
     recordBullet = async () => {
@@ -480,8 +482,8 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
     updateState = (exportState: GoogleApiClientUtils.Docs.ReadResult, dataDoc: Doc) => {
         let pullSuccess = false;
         if (exportState !== undefined && exportState.body !== undefined && exportState.title !== undefined) {
-            let data = Cast(dataDoc.data, RichTextField);
-            if (data) {
+            const data = Cast(dataDoc.data, RichTextField);
+            if (data instanceof RichTextField) {
                 pullSuccess = true;
                 this.isGoogleDocsUpdate = true;
                 dataDoc.data = new RichTextField(data[FromPlainText](exportState.body));
@@ -492,7 +494,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
             delete dataDoc[GoogleRef];
         }
         DocumentDecorations.Instance.startPullOutcome(pullSuccess);
-        this.tryUpdateHeight();
+        setTimeout(() => this.tryUpdateHeight(), 0);
     }
 
     checkState = (exportState: GoogleApiClientUtils.Docs.ReadResult, dataDoc: Doc) => {
@@ -630,7 +632,6 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
             if (!this.props.isOverlay) this.props.select(false);
             else this._editorView!.focus();
         }
-        this.tryUpdateHeight();
     }
 
     componentWillUnmount() {
-- 
cgit v1.2.3-70-g09d2


From 76a693012866178a3fbe037ab06cfd4482f37917 Mon Sep 17 00:00:00 2001
From: monikahedman <monika_hedman@brown.edu>
Date: Wed, 21 Aug 2019 14:22:30 -0400
Subject: djlzdkfj

---
 src/client/views/nodes/FormattedTextBox.tsx |  7 +++++++
 src/client/views/nodes/WebBox.tsx           | 26 ++++++++++++++++----------
 2 files changed, 23 insertions(+), 10 deletions(-)

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

diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 25f611f19..d299bbf72 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -162,6 +162,13 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
         }
     }
 
+    public setText = (text: string) => {
+        const tx = this._editorView!.state.tr.insertText(text);
+        const state = this._editorView!.state;
+        this._editorView!.dispatch(tx);
+        return new RichTextField(JSON.stringify(state.toJSON()));
+    }
+
     dispatchTransaction = (tx: Transaction) => {
         if (this._editorView) {
             const state = this._editorView.state.apply(tx);
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index c43b90f91..e7bed3bed 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -26,6 +26,8 @@ import { SelectionManager } from "../../util/SelectionManager";
 import { CollectionView } from "../collections/CollectionView";
 import { CollectionPDFView } from "../collections/CollectionPDFView";
 import { CollectionVideoView } from "../collections/CollectionVideoView";
+import { DocumentView } from "./DocumentView";
+import { FormattedTextBox } from "./FormattedTextBox";
 
 library.add(faStickyNote)
 
@@ -85,14 +87,15 @@ export class WebBox extends React.Component<FieldViewProps> {
         let field = Cast(this.props.Document[this.props.fieldKey], WebField);
         if (field) url = field.url.href;
 
-        let parent: Opt<CollectionView | CollectionPDFView | CollectionVideoView>;
+        let docView: DocumentView;
         // let parentDoc: any;
         SelectionManager.SelectedDocuments().map(dv => {
-            parent = dv.props.ContainingCollectionView;
-            // if(parent) parentDoc = parent.props.Document;
+            // docView = dv;
             dv.props.removeDocument && dv.props.removeDocument(dv.props.Document);
         });
 
+        console.log("happening")
+
         // // let newPoint = PreviewCursor._getTransform().transformPoint(PreviewCursor._clickPoint[0], PreviewCursor._clickPoint[1]);
         let newBox = Docs.Create.TextDocument({
             width: 200, height: 100,
@@ -103,13 +106,16 @@ export class WebBox extends React.Component<FieldViewProps> {
             title: url
         });
 
-        console.log(newBox)
-        if (parent) {
-            let parentDoc: Doc = parent.props.Document;
-            if (parentDoc && parentDoc.props) {
-                parentDoc.props.addDocument();
-            }
-        }
+        console.log(typeof newBox)
+
+        // const script = KeyValueBox.CompileKVPScript(`new RichTextField("{"doc":{"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"${url}"}]}]},"selection":{"type":"text","anchor":1,"head":1}}")`);
+        // const script = KeyValueBox.CompileKVPScript(newBox.setText(url))
+        // console.log(script)
+        // if (!script) return;
+        // KeyValueBox.ApplyKVPScript(this.props.Document, "data", script);
+
+        console.log(newBox);
+
 
         newBox.proto!.autoHeight = true;
         // PreviewCursor._addLiveTextDoc(newBox);
-- 
cgit v1.2.3-70-g09d2


From e50dc35f922efdeadfde70c9cf552b9ed5722810 Mon Sep 17 00:00:00 2001
From: Sam Wilkins <samwilkins333@gmail.com>
Date: Wed, 21 Aug 2019 14:35:35 -0400
Subject: uncommented terminators

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

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

diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 505257e9c..1e0975b4b 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -284,7 +284,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
         let results = await DictationManager.Controls.listen({
             interimHandler: this.setCurrentBulletContent,
             continuous: { indefinite: false },
-            // terminators: [completedCue, "bullet", "next"]
+            terminators: [completedCue, "bullet", "next"]
         });
         if (results && [DictationManager.Controls.Infringed, completedCue].includes(results)) {
             DictationManager.Controls.stop();
-- 
cgit v1.2.3-70-g09d2


From 88454c8163115b1396a34f4836b5f6f04817a3f0 Mon Sep 17 00:00:00 2001
From: Sam Wilkins <samwilkins333@gmail.com>
Date: Wed, 21 Aug 2019 16:11:20 -0400
Subject: tryupdateheight fixes

---
 src/client/views/DocumentDecorations.tsx    |  4 ++--
 src/client/views/nodes/FormattedTextBox.tsx | 26 +++++++++++++-------------
 2 files changed, 15 insertions(+), 15 deletions(-)

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

diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index cc8e57af9..a28088032 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -714,7 +714,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
         let canPull = this.targetDoc.data && this.targetDoc.data instanceof RichTextField;
         let dataDoc = Doc.GetProto(this.targetDoc);
         if (!canPull || !dataDoc[GoogleRef]) return (null);
-        let icon = !dataDoc.unchanged ? (this.pullIcon as any) : fetch;
+        let icon = dataDoc.unchanged === false ? (this.pullIcon as any) : fetch;
         icon = this.openHover ? "share" : icon;
         let animation = this.isAnimatingFetch ? "spin 0.5s linear infinite" : "none";
         let title = `${!dataDoc.unchanged ? "Pull from" : "Fetch"} Google Docs`;
@@ -727,7 +727,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
                         backgroundColor: this.pullColor,
                         transition: "0.2s ease all"
                     }}
-                    onPointerEnter={e => e.ctrlKey && runInAction(() => this.openHover = true)}
+                    onPointerEnter={e => e.altKey && runInAction(() => this.openHover = true)}
                     onPointerLeave={() => runInAction(() => this.openHover = false)}
                     onClick={e => {
                         if (e.altKey) {
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 1e0975b4b..c8722c6e3 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -1,6 +1,6 @@
 import { library } from '@fortawesome/fontawesome-svg-core';
 import { faEdit, faSmile, faTextHeight, faUpload } from '@fortawesome/free-solid-svg-icons';
-import { action, computed, IReactionDisposer, Lambda, observable, reaction, runInAction } from "mobx";
+import { action, computed, IReactionDisposer, Lambda, observable, reaction, runInAction, autorun } from "mobx";
 import { observer } from "mobx-react";
 import { baseKeymap } from "prosemirror-commands";
 import { history } from "prosemirror-history";
@@ -87,7 +87,6 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
     private pushReactionDisposer: Opt<IReactionDisposer>;
     private dropDisposer?: DragManager.DragDropDisposer;
     public get CurrentDiv(): HTMLDivElement { return this._ref.current!; }
-    private isGoogleDocsUpdate = false;
     @observable _entered = false;
 
     @observable public static InputBoxOverlay?: FormattedTextBox = undefined;
@@ -321,7 +320,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
     private newListItems = (count: number) => {
         let listItems: any[] = [];
         for (let i = 0; i < count; i++) {
-            listItems.push(schema.nodes.list_item.create(null, schema.nodes.paragraph.create(null)));
+            listItems.push(schema.nodes.list_item.create(undefined, schema.nodes.paragraph.create()));
         }
         return listItems;
     }
@@ -359,7 +358,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
         }
 
         this.pullFromGoogleDoc(this.checkState);
-        runInAction(() => DocumentDecorations.Instance.isAnimatingFetch = true);
+        this.dataDoc[GoogleRef] && this.dataDoc.unchanged && runInAction(() => DocumentDecorations.Instance.isAnimatingFetch = true);
 
         this._reactionDisposer = reaction(
             () => {
@@ -370,13 +369,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
                 if (this._editorView && !this._applyingChange) {
                     let updatedState = JSON.parse(incomingValue);
                     this._editorView.updateState(EditorState.fromJSON(config, updatedState));
-                    // manually sets cursor selection at the end of the text on focus
-                    if (this.isGoogleDocsUpdate) {
-                        this.isGoogleDocsUpdate = false;
-                        let end = this._editorView.state.doc.content.size - 1;
-                        updatedState.selection = { type: "text", anchor: end, head: end };
-                        this._editorView.updateState(EditorState.fromJSON(config, updatedState));
-                    }
+                    this.tryUpdateHeight();
                 }
             }
         );
@@ -485,16 +478,22 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
             const data = Cast(dataDoc.data, RichTextField);
             if (data instanceof RichTextField) {
                 pullSuccess = true;
-                this.isGoogleDocsUpdate = true;
                 dataDoc.data = new RichTextField(data[FromPlainText](exportState.body));
+                setTimeout(() => {
+                    if (this._editorView) {
+                        let state = this._editorView.state;
+                        let end = state.doc.content.size - 1;
+                        this._editorView.dispatch(state.tr.setSelection(TextSelection.create(state.doc, end, end)));
+                    }
+                }, 0);
                 dataDoc.title = exportState.title;
+                this.Document.customTitle = true;
                 dataDoc.unchanged = true;
             }
         } else {
             delete dataDoc[GoogleRef];
         }
         DocumentDecorations.Instance.startPullOutcome(pullSuccess);
-        setTimeout(() => this.tryUpdateHeight(), 0);
     }
 
     checkState = (exportState: GoogleApiClientUtils.Docs.ReadResult, dataDoc: Doc) => {
@@ -719,6 +718,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
     onFocused = (e: React.FocusEvent): void => {
         document.removeEventListener("keypress", this.recordKeyHandler);
         document.addEventListener("keypress", this.recordKeyHandler);
+        this.tryUpdateHeight();
         if (!this.props.isOverlay) {
             FormattedTextBox.InputBoxOverlay = this;
         } else {
-- 
cgit v1.2.3-70-g09d2


From f4888ec4b2862cdf890ac1b0f6670b41398266df Mon Sep 17 00:00:00 2001
From: Sam Wilkins <samwilkins333@gmail.com>
Date: Wed, 21 Aug 2019 20:01:35 -0400
Subject: can create google slides presentations

---
 .../apis/google_docs/GoogleApiClientUtils.ts       | 99 +++++++++++++---------
 src/client/views/MainView.tsx                      |  4 +
 src/client/views/nodes/FormattedTextBox.tsx        | 20 ++---
 src/server/apis/google/GoogleApiServerUtils.ts     | 65 +++++++++-----
 src/server/index.ts                                | 19 ++---
 5 files changed, 123 insertions(+), 84 deletions(-)

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

diff --git a/src/client/apis/google_docs/GoogleApiClientUtils.ts b/src/client/apis/google_docs/GoogleApiClientUtils.ts
index 821c52270..52452cd95 100644
--- a/src/client/apis/google_docs/GoogleApiClientUtils.ts
+++ b/src/client/apis/google_docs/GoogleApiClientUtils.ts
@@ -1,4 +1,4 @@
-import { docs_v1 } from "googleapis";
+import { docs_v1, slides_v1 } from "googleapis";
 import { PostToServer } from "../../../Utils";
 import { RouteStore } from "../../../server/RouteStore";
 import { Opt } from "../../../new_fields/Doc";
@@ -9,47 +9,47 @@ export const Pushes = "googleDocsPushCount";
 
 export namespace GoogleApiClientUtils {
 
-    export namespace Docs {
+    export enum Actions {
+        Create = "create",
+        Retrieve = "retrieve",
+        Update = "update"
+    }
 
-        export enum Actions {
-            Create = "create",
-            Retrieve = "retrieve",
-            Update = "update"
-        }
+    export enum WriteMode {
+        Insert,
+        Replace
+    }
 
-        export enum WriteMode {
-            Insert,
-            Replace
-        }
+    export type DocumentId = string;
+    export type Reference = DocumentId | CreateOptions;
+    export type TextContent = string | string[];
+    export type IdHandler = (id: DocumentId) => any;
+    export type CreationResult = Opt<DocumentId>;
+    export type ReadLinesResult = Opt<{ title?: string, bodyLines?: string[] }>;
+    export type ReadResult = { title?: string, body?: string };
 
-        export type DocumentId = string;
-        export type Reference = DocumentId | CreateOptions;
-        export type TextContent = string | string[];
-        export type IdHandler = (id: DocumentId) => any;
+    export interface CreateOptions {
+        title?: string; // if excluded, will use a default title annotated with the current date
+    }
 
-        export type CreationResult = Opt<DocumentId>;
-        export type RetrievalResult = Opt<docs_v1.Schema$Document>;
-        export type UpdateResult = Opt<docs_v1.Schema$BatchUpdateDocumentResponse>;
-        export type ReadLinesResult = Opt<{ title?: string, bodyLines?: string[] }>;
-        export type ReadResult = { title?: string, body?: string };
+    export interface RetrieveOptions {
+        documentId: DocumentId;
+    }
 
-        export interface CreateOptions {
-            handler: IdHandler; // callback to process the documentId of the newly created Google Doc
-            title?: string; // if excluded, will use a default title annotated with the current date
-        }
+    export type ReadOptions = RetrieveOptions & { removeNewlines?: boolean };
 
-        export interface RetrieveOptions {
-            documentId: DocumentId;
-        }
+    export interface WriteOptions {
+        mode: WriteMode;
+        content: TextContent;
+        reference: Reference;
+        index?: number; // if excluded, will compute the last index of the document and append the content there
+    }
 
-        export type ReadOptions = RetrieveOptions & { removeNewlines?: boolean };
 
-        export interface WriteOptions {
-            mode: WriteMode;
-            content: TextContent;
-            reference: Reference;
-            index?: number; // if excluded, will compute the last index of the document and append the content there
-        }
+    export namespace Docs {
+
+        export type RetrievalResult = Opt<docs_v1.Schema$Document>;
+        export type UpdateResult = Opt<docs_v1.Schema$BatchUpdateDocumentResponse>;
 
         export interface UpdateOptions {
             documentId: DocumentId;
@@ -106,7 +106,7 @@ export namespace GoogleApiClientUtils {
          * @returns the documentId of the newly generated document, or undefined if the creation process fails.
          */
         export const create = async (options: CreateOptions): Promise<CreationResult> => {
-            const path = RouteStore.googleDocs + Actions.Create;
+            const path = RouteStore.googleDocs + "Documents/" + Actions.Create;
             const parameters = {
                 requestBody: {
                     title: options.title || `Dash Export (${new Date().toDateString()})`
@@ -115,17 +115,14 @@ export namespace GoogleApiClientUtils {
             try {
                 const schema: docs_v1.Schema$Document = await PostToServer(path, parameters);
                 const generatedId = schema.documentId;
-                if (generatedId) {
-                    options.handler(generatedId);
-                    return generatedId;
-                }
+                return generatedId;
             } catch {
                 return undefined;
             }
         };
 
         export const retrieve = async (options: RetrieveOptions): Promise<RetrievalResult> => {
-            const path = RouteStore.googleDocs + Actions.Retrieve;
+            const path = RouteStore.googleDocs + "Documents/" + Actions.Retrieve;
             try {
                 const schema: RetrievalResult = await PostToServer(path, options);
                 return schema;
@@ -135,7 +132,7 @@ export namespace GoogleApiClientUtils {
         };
 
         export const update = async (options: UpdateOptions): Promise<UpdateResult> => {
-            const path = RouteStore.googleDocs + Actions.Update;
+            const path = RouteStore.googleDocs + "Documents/" + Actions.Update;
             const parameters = {
                 documentId: options.documentId,
                 requestBody: {
@@ -221,4 +218,24 @@ export namespace GoogleApiClientUtils {
 
     }
 
+    export namespace Slides {
+
+        export const create = async (options: CreateOptions): Promise<CreationResult> => {
+            const path = RouteStore.googleDocs + "Slides/" + Actions.Create;
+            const parameters = {
+                requestBody: {
+                    title: options.title || `Dash Export (${new Date().toDateString()})`
+                }
+            };
+            try {
+                const schema: slides_v1.Schema$Presentation = await PostToServer(path, parameters);
+                const generatedId = schema.presentationId;
+                return generatedId;
+            } catch {
+                return undefined;
+            }
+        };
+
+    }
+
 }
\ No newline at end of file
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index f28844009..3490a0f68 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -40,6 +40,7 @@ import { PreviewCursor } from './PreviewCursor';
 import { FilterBox } from './search/FilterBox';
 import PresModeMenu from './presentationview/PresentationModeMenu';
 import { PresBox } from './nodes/PresBox';
+import { GoogleApiClientUtils } from '../apis/google_docs/GoogleApiClientUtils';
 
 @observer
 export class MainView extends React.Component {
@@ -120,6 +121,9 @@ export class MainView extends React.Component {
     componentWillMount() {
         var tag = document.createElement('script');
 
+        let title = "THIS IS MY FIRST DASH PRESENTATION";
+        GoogleApiClientUtils.Slides.create({ title }).then(id => console.log("We received this! ", id));
+
         tag.src = "https://www.youtube.com/iframe_api";
         var firstScriptTag = document.getElementsByTagName('script')[0];
         firstScriptTag.parentNode!.insertBefore(tag, firstScriptTag);
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index c8722c6e3..408a6948e 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -64,7 +64,7 @@ export const GoogleRef = "googleDocId";
 type RichTextDocument = makeInterface<[typeof richTextSchema]>;
 const RichTextDocument = makeInterface(richTextSchema);
 
-type PullHandler = (exportState: GoogleApiClientUtils.Docs.ReadResult, dataDoc: Doc) => void;
+type PullHandler = (exportState: GoogleApiClientUtils.ReadResult, dataDoc: Doc) => void;
 
 @observer
 export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTextBoxProps), RichTextDocument>(RichTextDocument) {
@@ -430,22 +430,20 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
     }
 
     pushToGoogleDoc = async () => {
-        this.pullFromGoogleDoc(async (exportState: GoogleApiClientUtils.Docs.ReadResult, dataDoc: Doc) => {
-            let modes = GoogleApiClientUtils.Docs.WriteMode;
+        this.pullFromGoogleDoc(async (exportState: GoogleApiClientUtils.ReadResult, dataDoc: Doc) => {
+            let modes = GoogleApiClientUtils.WriteMode;
             let mode = modes.Replace;
-            let reference: Opt<GoogleApiClientUtils.Docs.Reference> = Cast(this.dataDoc[GoogleRef], "string");
+            let reference: Opt<GoogleApiClientUtils.Reference> = Cast(this.dataDoc[GoogleRef], "string");
             if (!reference) {
                 mode = modes.Insert;
-                reference = {
-                    title: StrCast(this.dataDoc.title),
-                    handler: id => this.dataDoc[GoogleRef] = id
-                };
+                reference = { title: StrCast(this.dataDoc.title) };
             }
             let redo = async () => {
                 let data = Cast(this.dataDoc.data, RichTextField);
                 if (this._editorView && reference && data) {
                     let content = data[ToPlainText]();
                     let response = await GoogleApiClientUtils.Docs.write({ reference, content, mode });
+                    response && (this.dataDoc[GoogleRef] = response.documentId);
                     let pushSuccess = response !== undefined && !("errors" in response);
                     dataDoc.unchanged = pushSuccess;
                     DocumentDecorations.Instance.startPushOutcome(pushSuccess);
@@ -465,14 +463,14 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
     pullFromGoogleDoc = async (handler: PullHandler) => {
         let dataDoc = this.dataDoc;
         let documentId = StrCast(dataDoc[GoogleRef]);
-        let exportState: GoogleApiClientUtils.Docs.ReadResult = {};
+        let exportState: GoogleApiClientUtils.ReadResult = {};
         if (documentId) {
             exportState = await GoogleApiClientUtils.Docs.read({ documentId });
         }
         UndoManager.RunInBatch(() => handler(exportState, dataDoc), Pulls);
     }
 
-    updateState = (exportState: GoogleApiClientUtils.Docs.ReadResult, dataDoc: Doc) => {
+    updateState = (exportState: GoogleApiClientUtils.ReadResult, dataDoc: Doc) => {
         let pullSuccess = false;
         if (exportState !== undefined && exportState.body !== undefined && exportState.title !== undefined) {
             const data = Cast(dataDoc.data, RichTextField);
@@ -496,7 +494,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
         DocumentDecorations.Instance.startPullOutcome(pullSuccess);
     }
 
-    checkState = (exportState: GoogleApiClientUtils.Docs.ReadResult, dataDoc: Doc) => {
+    checkState = (exportState: GoogleApiClientUtils.ReadResult, dataDoc: Doc) => {
         if (exportState !== undefined && exportState.body !== undefined && exportState.title !== undefined) {
             let data = Cast(dataDoc.data, RichTextField);
             if (data) {
diff --git a/src/server/apis/google/GoogleApiServerUtils.ts b/src/server/apis/google/GoogleApiServerUtils.ts
index 817b2b696..ff027c501 100644
--- a/src/server/apis/google/GoogleApiServerUtils.ts
+++ b/src/server/apis/google/GoogleApiServerUtils.ts
@@ -1,7 +1,10 @@
-import { google, docs_v1 } from "googleapis";
+import { google, docs_v1, slides_v1 } from "googleapis";
 import { createInterface } from "readline";
 import { readFile, writeFile } from "fs";
 import { OAuth2Client } from "google-auth-library";
+import { Opt } from "../../../new_fields/Doc";
+import { GlobalOptions } from "googleapis-common";
+import { GaxiosResponse } from "gaxios";
 
 /**
  * Server side authentication for Google Api queries.
@@ -13,38 +16,57 @@ export namespace GoogleApiServerUtils {
     const SCOPES = [
         'documents.readonly',
         'documents',
+        'presentations',
+        'presentations.readonly',
         'drive',
         'drive.file',
     ];
-    // The file token.json stores the user's access and refresh tokens, and is
-    // created automatically when the authorization flow completes for the first
-    // time.
+
     export const parseBuffer = (data: Buffer) => JSON.parse(data.toString());
 
-    export namespace Docs {
+    export enum Sector {
+        Documents = "Documents",
+        Slides = "Slides"
+    }
+
 
-        export interface CredentialPaths {
-            credentials: string;
-            token: string;
-        }
+    export interface CredentialPaths {
+        credentials: string;
+        token: string;
+    }
 
-        export type Endpoint = docs_v1.Docs;
+    export type ApiResponse = Promise<GaxiosResponse>;
+    export type ApiRouter = (endpoint: Endpoint, paramters: any) => ApiResponse;
+    export type ApiHandler = (parameters: any) => ApiResponse;
+    export type Action = "create" | "retrieve" | "update";
 
-        export const GetEndpoint = async (paths: CredentialPaths) => {
-            return new Promise<Endpoint>((resolve, reject) => {
-                readFile(paths.credentials, (err, credentials) => {
-                    if (err) {
-                        reject(err);
-                        return console.log('Error loading client secret file:', err);
+    export type Endpoint = { get: ApiHandler, create: ApiHandler, batchUpdate: ApiHandler };
+    export type EndpointParameters = GlobalOptions & { version: "v1" };
+
+    export const GetEndpoint = async (sector: string, paths: CredentialPaths) => {
+        return new Promise<Opt<Endpoint>>((resolve, reject) => {
+            readFile(paths.credentials, (err, credentials) => {
+                if (err) {
+                    reject(err);
+                    return console.log('Error loading client secret file:', err);
+                }
+                return authorize(parseBuffer(credentials), paths.token).then(auth => {
+                    let routed: Opt<Endpoint>;
+                    let parameters: EndpointParameters = { auth, version: "v1" };
+                    switch (sector) {
+                        case Sector.Documents:
+                            routed = google.docs(parameters).documents;
+                            break;
+                        case Sector.Slides:
+                            routed = google.slides(parameters).presentations;
+                            break;
                     }
-                    return authorize(parseBuffer(credentials), paths.token).then(auth => {
-                        resolve(google.docs({ version: "v1", auth }));
-                    });
+                    resolve(routed);
                 });
             });
-        };
+        });
+    };
 
-    }
 
     /**
      * Create an OAuth2 client with the given credentials, and returns the promise resolving to the authenticated client
@@ -105,5 +127,4 @@ export namespace GoogleApiServerUtils {
             });
         });
     }
-
 }
\ No newline at end of file
diff --git a/src/server/index.ts b/src/server/index.ts
index ef1829f30..6aecb875a 100644
--- a/src/server/index.ts
+++ b/src/server/index.ts
@@ -45,6 +45,7 @@ import { GoogleApiServerUtils } from "./apis/google/GoogleApiServerUtils";
 import { GaxiosResponse } from 'gaxios';
 import { Opt } from '../new_fields/Doc';
 import { docs_v1 } from 'googleapis';
+import { Endpoint } from 'googleapis-common';
 const MongoStore = require('connect-mongo')(session);
 const mongoose = require('mongoose');
 const probe = require("probe-image-size");
@@ -799,21 +800,19 @@ function HandleYoutubeQuery([query, callback]: [YoutubeQueryInput, (result?: any
 const credentials = path.join(__dirname, "./credentials/google_docs_credentials.json");
 const token = path.join(__dirname, "./credentials/google_docs_token.json");
 
-type ApiResponse = Promise<GaxiosResponse>;
-type ApiHandler = (endpoint: docs_v1.Resource$Documents, parameters: any) => ApiResponse;
-type Action = "create" | "retrieve" | "update";
-
-const EndpointHandlerMap = new Map<Action, ApiHandler>([
+const EndpointHandlerMap = new Map<GoogleApiServerUtils.Action, GoogleApiServerUtils.ApiRouter>([
     ["create", (api, params) => api.create(params)],
     ["retrieve", (api, params) => api.get(params)],
     ["update", (api, params) => api.batchUpdate(params)],
 ]);
 
-app.post(RouteStore.googleDocs + ":action", (req, res) => {
-    GoogleApiServerUtils.Docs.GetEndpoint({ credentials, token }).then(endpoint => {
-        let handler = EndpointHandlerMap.get(req.params.action);
-        if (handler) {
-            let execute = handler(endpoint.documents, req.body).then(
+app.post(RouteStore.googleDocs + ":sector/:action", (req, res) => {
+    let sector = req.params.sector;
+    let action = req.params.action;
+    GoogleApiServerUtils.GetEndpoint(GoogleApiServerUtils.Sector[sector], { credentials, token }).then(endpoint => {
+        let handler = EndpointHandlerMap.get(action);
+        if (endpoint && handler) {
+            let execute = handler(endpoint, req.body).then(
                 response => res.send(response.data),
                 rejection => res.send(rejection)
             );
-- 
cgit v1.2.3-70-g09d2


From 30d55c5b91329d32a79b7135fff3566b2cd0e822 Mon Sep 17 00:00:00 2001
From: Sam Wilkins <samwilkins333@gmail.com>
Date: Wed, 21 Aug 2019 20:33:42 -0400
Subject: create is now shared between slides and docs

---
 .../apis/google_docs/GoogleApiClientUtils.ts       | 79 +++++++++-------------
 src/client/views/MainView.tsx                      |  2 +-
 src/client/views/nodes/FormattedTextBox.tsx        |  2 +-
 src/server/RouteStore.ts                           |  2 +-
 src/server/apis/google/GoogleApiServerUtils.ts     |  6 +-
 src/server/index.ts                                |  4 +-
 6 files changed, 40 insertions(+), 55 deletions(-)

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

diff --git a/src/client/apis/google_docs/GoogleApiClientUtils.ts b/src/client/apis/google_docs/GoogleApiClientUtils.ts
index 52452cd95..ea020ed00 100644
--- a/src/client/apis/google_docs/GoogleApiClientUtils.ts
+++ b/src/client/apis/google_docs/GoogleApiClientUtils.ts
@@ -9,6 +9,11 @@ export const Pushes = "googleDocsPushCount";
 
 export namespace GoogleApiClientUtils {
 
+    export enum Service {
+        Documents = "Documents",
+        Slides = "Slides"
+    }
+
     export enum Actions {
         Create = "create",
         Retrieve = "retrieve",
@@ -29,6 +34,7 @@ export namespace GoogleApiClientUtils {
     export type ReadResult = { title?: string, body?: string };
 
     export interface CreateOptions {
+        service: Service;
         title?: string; // if excluded, will use a default title annotated with the current date
     }
 
@@ -45,6 +51,30 @@ export namespace GoogleApiClientUtils {
         index?: number; // if excluded, will compute the last index of the document and append the content there
     }
 
+    /**
+    * After following the authentication routine, which connects this API call to the current signed in account
+    * and grants the appropriate permissions, this function programmatically creates an arbitrary Google Doc which
+    * should appear in the user's Google Doc library instantaneously.
+    * 
+    * @param options the title to assign to the new document, and the information necessary
+    * to store the new documentId returned from the creation process
+    * @returns the documentId of the newly generated document, or undefined if the creation process fails.
+    */
+    export const create = async (options: CreateOptions): Promise<CreationResult> => {
+        const path = `${RouteStore.googleDocs}/${options.service}/${Actions.Create}`;
+        const parameters = {
+            requestBody: {
+                title: options.title || `Dash Export (${new Date().toDateString()})`
+            }
+        };
+        try {
+            const schema: any = await PostToServer(path, parameters);
+            let key = ["document", "presentation"].find(prefix => `${prefix}Id` in schema) + "Id";
+            return schema[key];
+        } catch {
+            return undefined;
+        }
+    };
 
     export namespace Docs {
 
@@ -96,33 +126,8 @@ export namespace GoogleApiClientUtils {
 
         }
 
-        /**
-         * After following the authentication routine, which connects this API call to the current signed in account
-         * and grants the appropriate permissions, this function programmatically creates an arbitrary Google Doc which
-         * should appear in the user's Google Doc library instantaneously.
-         * 
-         * @param options the title to assign to the new document, and the information necessary
-         * to store the new documentId returned from the creation process
-         * @returns the documentId of the newly generated document, or undefined if the creation process fails.
-         */
-        export const create = async (options: CreateOptions): Promise<CreationResult> => {
-            const path = RouteStore.googleDocs + "Documents/" + Actions.Create;
-            const parameters = {
-                requestBody: {
-                    title: options.title || `Dash Export (${new Date().toDateString()})`
-                }
-            };
-            try {
-                const schema: docs_v1.Schema$Document = await PostToServer(path, parameters);
-                const generatedId = schema.documentId;
-                return generatedId;
-            } catch {
-                return undefined;
-            }
-        };
-
         export const retrieve = async (options: RetrieveOptions): Promise<RetrievalResult> => {
-            const path = RouteStore.googleDocs + "Documents/" + Actions.Retrieve;
+            const path = `${RouteStore.googleDocs}/${Service.Documents}/${Actions.Retrieve}`;
             try {
                 const schema: RetrievalResult = await PostToServer(path, options);
                 return schema;
@@ -132,7 +137,7 @@ export namespace GoogleApiClientUtils {
         };
 
         export const update = async (options: UpdateOptions): Promise<UpdateResult> => {
-            const path = RouteStore.googleDocs + "Documents/" + Actions.Update;
+            const path = `${RouteStore.googleDocs}/${Service.Documents}/${Actions.Update}`;
             const parameters = {
                 documentId: options.documentId,
                 requestBody: {
@@ -218,24 +223,4 @@ export namespace GoogleApiClientUtils {
 
     }
 
-    export namespace Slides {
-
-        export const create = async (options: CreateOptions): Promise<CreationResult> => {
-            const path = RouteStore.googleDocs + "Slides/" + Actions.Create;
-            const parameters = {
-                requestBody: {
-                    title: options.title || `Dash Export (${new Date().toDateString()})`
-                }
-            };
-            try {
-                const schema: slides_v1.Schema$Presentation = await PostToServer(path, parameters);
-                const generatedId = schema.presentationId;
-                return generatedId;
-            } catch {
-                return undefined;
-            }
-        };
-
-    }
-
 }
\ No newline at end of file
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 3490a0f68..2a219fdd1 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -122,7 +122,7 @@ export class MainView extends React.Component {
         var tag = document.createElement('script');
 
         let title = "THIS IS MY FIRST DASH PRESENTATION";
-        GoogleApiClientUtils.Slides.create({ title }).then(id => console.log("We received this! ", id));
+        GoogleApiClientUtils.create({ service: GoogleApiClientUtils.Service.Slides, title }).then(id => console.log("We received this! ", id));
 
         tag.src = "https://www.youtube.com/iframe_api";
         var firstScriptTag = document.getElementsByTagName('script')[0];
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 408a6948e..bcec6f7c3 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -436,7 +436,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
             let reference: Opt<GoogleApiClientUtils.Reference> = Cast(this.dataDoc[GoogleRef], "string");
             if (!reference) {
                 mode = modes.Insert;
-                reference = { title: StrCast(this.dataDoc.title) };
+                reference = { service: GoogleApiClientUtils.Service.Documents, title: StrCast(this.dataDoc.title) };
             }
             let redo = async () => {
                 let data = Cast(this.dataDoc.data, RichTextField);
diff --git a/src/server/RouteStore.ts b/src/server/RouteStore.ts
index 5d977006a..014906054 100644
--- a/src/server/RouteStore.ts
+++ b/src/server/RouteStore.ts
@@ -31,6 +31,6 @@ export enum RouteStore {
 
     // APIS
     cognitiveServices = "/cognitiveservices",
-    googleDocs = "/googleDocs/"
+    googleDocs = "/googleDocs"
 
 }
\ No newline at end of file
diff --git a/src/server/apis/google/GoogleApiServerUtils.ts b/src/server/apis/google/GoogleApiServerUtils.ts
index ff027c501..8785cd974 100644
--- a/src/server/apis/google/GoogleApiServerUtils.ts
+++ b/src/server/apis/google/GoogleApiServerUtils.ts
@@ -24,7 +24,7 @@ export namespace GoogleApiServerUtils {
 
     export const parseBuffer = (data: Buffer) => JSON.parse(data.toString());
 
-    export enum Sector {
+    export enum Service {
         Documents = "Documents",
         Slides = "Slides"
     }
@@ -54,10 +54,10 @@ export namespace GoogleApiServerUtils {
                     let routed: Opt<Endpoint>;
                     let parameters: EndpointParameters = { auth, version: "v1" };
                     switch (sector) {
-                        case Sector.Documents:
+                        case Service.Documents:
                             routed = google.docs(parameters).documents;
                             break;
-                        case Sector.Slides:
+                        case Service.Slides:
                             routed = google.slides(parameters).presentations;
                             break;
                     }
diff --git a/src/server/index.ts b/src/server/index.ts
index 6aecb875a..0476bf3df 100644
--- a/src/server/index.ts
+++ b/src/server/index.ts
@@ -806,10 +806,10 @@ const EndpointHandlerMap = new Map<GoogleApiServerUtils.Action, GoogleApiServerU
     ["update", (api, params) => api.batchUpdate(params)],
 ]);
 
-app.post(RouteStore.googleDocs + ":sector/:action", (req, res) => {
+app.post(RouteStore.googleDocs + "/:sector/:action", (req, res) => {
     let sector = req.params.sector;
     let action = req.params.action;
-    GoogleApiServerUtils.GetEndpoint(GoogleApiServerUtils.Sector[sector], { credentials, token }).then(endpoint => {
+    GoogleApiServerUtils.GetEndpoint(GoogleApiServerUtils.Service[sector], { credentials, token }).then(endpoint => {
         let handler = EndpointHandlerMap.get(action);
         if (endpoint && handler) {
             let execute = handler(endpoint, req.body).then(
-- 
cgit v1.2.3-70-g09d2


From e68b1cc60b2a8ffe55eea3e1d5266d6897dcdcb6 Mon Sep 17 00:00:00 2001
From: Sam Wilkins <samwilkins333@gmail.com>
Date: Wed, 21 Aug 2019 21:31:17 -0400
Subject: integrated slides

---
 .../apis/google_docs/GoogleApiClientUtils.ts       |    47 +-
 src/client/views/MainView.tsx                      |     3 -
 src/client/views/nodes/FormattedTextBox.tsx        |     2 +-
 src/server/slides.json                             | 10820 +++++++++++++++++++
 4 files changed, 10851 insertions(+), 21 deletions(-)
 create mode 100644 src/server/slides.json

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

diff --git a/src/client/apis/google_docs/GoogleApiClientUtils.ts b/src/client/apis/google_docs/GoogleApiClientUtils.ts
index ea020ed00..3e90adc4d 100644
--- a/src/client/apis/google_docs/GoogleApiClientUtils.ts
+++ b/src/client/apis/google_docs/GoogleApiClientUtils.ts
@@ -25,11 +25,11 @@ export namespace GoogleApiClientUtils {
         Replace
     }
 
-    export type DocumentId = string;
-    export type Reference = DocumentId | CreateOptions;
+    export type Identifier = string;
+    export type Reference = Identifier | CreateOptions;
     export type TextContent = string | string[];
-    export type IdHandler = (id: DocumentId) => any;
-    export type CreationResult = Opt<DocumentId>;
+    export type IdHandler = (id: Identifier) => any;
+    export type CreationResult = Opt<Identifier>;
     export type ReadLinesResult = Opt<{ title?: string, bodyLines?: string[] }>;
     export type ReadResult = { title?: string, body?: string };
 
@@ -39,10 +39,14 @@ export namespace GoogleApiClientUtils {
     }
 
     export interface RetrieveOptions {
-        documentId: DocumentId;
+        service: Service;
+        identifier: Identifier;
     }
 
-    export type ReadOptions = RetrieveOptions & { removeNewlines?: boolean };
+    export interface ReadOptions {
+        identifier: Identifier;
+        removeNewlines?: boolean;
+    }
 
     export interface WriteOptions {
         mode: WriteMode;
@@ -78,11 +82,11 @@ export namespace GoogleApiClientUtils {
 
     export namespace Docs {
 
-        export type RetrievalResult = Opt<docs_v1.Schema$Document>;
+        export type RetrievalResult = Opt<docs_v1.Schema$Document | slides_v1.Schema$Presentation>;
         export type UpdateResult = Opt<docs_v1.Schema$BatchUpdateDocumentResponse>;
 
         export interface UpdateOptions {
-            documentId: DocumentId;
+            documentId: Identifier;
             requests: docs_v1.Schema$Request[];
         }
 
@@ -126,11 +130,20 @@ export namespace GoogleApiClientUtils {
 
         }
 
+        const KeyMapping = new Map<Service, string>([
+            [Service.Documents, "documentId"],
+            [Service.Slides, "presentationId"]
+        ]);
+
         export const retrieve = async (options: RetrieveOptions): Promise<RetrievalResult> => {
-            const path = `${RouteStore.googleDocs}/${Service.Documents}/${Actions.Retrieve}`;
+            const path = `${RouteStore.googleDocs}/${options.service}/${Actions.Retrieve}`;
             try {
-                const schema: RetrievalResult = await PostToServer(path, options);
-                return schema;
+                let parameters: any = {}, key: string | undefined;
+                if ((key = KeyMapping.get(options.service))) {
+                    parameters[key] = options.identifier;
+                    const schema: RetrievalResult = await PostToServer(path, parameters);
+                    return schema;
+                }
             } catch {
                 return undefined;
             }
@@ -153,7 +166,7 @@ export namespace GoogleApiClientUtils {
         };
 
         export const read = async (options: ReadOptions): Promise<ReadResult> => {
-            return retrieve(options).then(document => {
+            return retrieve({ ...options, service: Service.Documents }).then(document => {
                 let result: ReadResult = {};
                 if (document) {
                     let title = document.title;
@@ -165,7 +178,7 @@ export namespace GoogleApiClientUtils {
         };
 
         export const readLines = async (options: ReadOptions): Promise<ReadLinesResult> => {
-            return retrieve(options).then(document => {
+            return retrieve({ ...options, service: Service.Documents }).then(document => {
                 let result: ReadLinesResult = {};
                 if (document) {
                     let title = document.title;
@@ -179,14 +192,14 @@ export namespace GoogleApiClientUtils {
 
         export const write = async (options: WriteOptions): Promise<UpdateResult> => {
             const requests: docs_v1.Schema$Request[] = [];
-            const documentId = await Utils.initialize(options.reference);
-            if (!documentId) {
+            const identifier = await Utils.initialize(options.reference);
+            if (!identifier) {
                 return undefined;
             }
             let index = options.index;
             const mode = options.mode;
             if (!(index && mode === WriteMode.Insert)) {
-                let schema = await retrieve({ documentId });
+                let schema = await retrieve({ identifier, service: Service.Documents });
                 if (!schema || !(index = Utils.endOf(schema))) {
                     return undefined;
                 }
@@ -212,7 +225,7 @@ export namespace GoogleApiClientUtils {
             if (!requests.length) {
                 return undefined;
             }
-            let replies: any = await update({ documentId, requests });
+            let replies: any = await update({ documentId: identifier, requests });
             let errors = "errors";
             if (errors in replies) {
                 console.log("Write operation failed:");
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 2a219fdd1..0286a201b 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -121,9 +121,6 @@ export class MainView extends React.Component {
     componentWillMount() {
         var tag = document.createElement('script');
 
-        let title = "THIS IS MY FIRST DASH PRESENTATION";
-        GoogleApiClientUtils.create({ service: GoogleApiClientUtils.Service.Slides, title }).then(id => console.log("We received this! ", id));
-
         tag.src = "https://www.youtube.com/iframe_api";
         var firstScriptTag = document.getElementsByTagName('script')[0];
         firstScriptTag.parentNode!.insertBefore(tag, firstScriptTag);
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index bcec6f7c3..a603676bb 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -465,7 +465,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
         let documentId = StrCast(dataDoc[GoogleRef]);
         let exportState: GoogleApiClientUtils.ReadResult = {};
         if (documentId) {
-            exportState = await GoogleApiClientUtils.Docs.read({ documentId });
+            exportState = await GoogleApiClientUtils.Docs.read({ identifier: documentId });
         }
         UndoManager.RunInBatch(() => handler(exportState, dataDoc), Pulls);
     }
diff --git a/src/server/slides.json b/src/server/slides.json
new file mode 100644
index 000000000..323cac3a6
--- /dev/null
+++ b/src/server/slides.json
@@ -0,0 +1,10820 @@
+{
+    "presentationId": "1gHxyT6bBhsPVeuWNnWDzI33yEviMVo8n60JtZiVy3tY",
+    "pageSize": {
+        "width": {
+            "magnitude": 9144000,
+            "unit": "EMU"
+        },
+        "height": {
+            "magnitude": 5143500,
+            "unit": "EMU"
+        }
+    },
+    "slides": [
+        {
+            "objectId": "p",
+            "pageElements": [
+                {
+                    "objectId": "i0",
+                    "size": {
+                        "width": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        },
+                        "height": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        }
+                    },
+                    "transform": {
+                        "scaleX": 2.8402,
+                        "scaleY": 0.6842,
+                        "translateX": 311708.35000000003,
+                        "translateY": 744575,
+                        "unit": "EMU"
+                    },
+                    "shape": {
+                        "shapeType": "TEXT_BOX",
+                        "text": {
+                            "textElements": [
+                                {
+                                    "endIndex": 20,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        }
+                                    }
+                                },
+                                {
+                                    "endIndex": 20,
+                                    "textRun": {
+                                        "content": "Importing into Dash\n",
+                                        "style": {}
+                                    }
+                                }
+                            ]
+                        },
+                        "shapeProperties": {
+                            "shapeBackgroundFill": {
+                                "propertyState": "INHERIT"
+                            },
+                            "outline": {
+                                "propertyState": "INHERIT"
+                            },
+                            "shadow": {
+                                "propertyState": "INHERIT"
+                            }
+                        },
+                        "placeholder": {
+                            "type": "CENTERED_TITLE",
+                            "parentObjectId": "p2_i0"
+                        }
+                    }
+                },
+                {
+                    "objectId": "i1",
+                    "size": {
+                        "width": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        },
+                        "height": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        }
+                    },
+                    "transform": {
+                        "scaleX": 2.8402,
+                        "scaleY": 0.2642,
+                        "translateX": 311700,
+                        "translateY": 2834125,
+                        "unit": "EMU"
+                    },
+                    "shape": {
+                        "shapeType": "TEXT_BOX",
+                        "text": {
+                            "textElements": [
+                                {
+                                    "endIndex": 15,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        }
+                                    }
+                                },
+                                {
+                                    "endIndex": 15,
+                                    "textRun": {
+                                        "content": "By Sam Wilkins\n",
+                                        "style": {}
+                                    }
+                                }
+                            ]
+                        },
+                        "shapeProperties": {
+                            "shapeBackgroundFill": {
+                                "propertyState": "INHERIT"
+                            },
+                            "outline": {
+                                "propertyState": "INHERIT"
+                            },
+                            "shadow": {
+                                "propertyState": "INHERIT"
+                            }
+                        },
+                        "placeholder": {
+                            "type": "SUBTITLE",
+                            "parentObjectId": "p2_i1"
+                        }
+                    }
+                }
+            ],
+            "slideProperties": {
+                "layoutObjectId": "p2",
+                "masterObjectId": "simple-light-2",
+                "notesPage": {
+                    "objectId": "p:notes",
+                    "pageType": "NOTES",
+                    "pageElements": [
+                        {
+                            "objectId": "i2",
+                            "size": {
+                                "width": {
+                                    "magnitude": 3000000,
+                                    "unit": "EMU"
+                                },
+                                "height": {
+                                    "magnitude": 3000000,
+                                    "unit": "EMU"
+                                }
+                            },
+                            "transform": {
+                                "scaleX": 2.032025,
+                                "scaleY": 1.143,
+                                "translateX": 381300,
+                                "translateY": 685800,
+                                "unit": "EMU"
+                            },
+                            "shape": {
+                                "shapeProperties": {
+                                    "outline": {
+                                        "propertyState": "INHERIT"
+                                    }
+                                },
+                                "placeholder": {
+                                    "type": "SLIDE_IMAGE",
+                                    "parentObjectId": "n:slide"
+                                }
+                            }
+                        },
+                        {
+                            "objectId": "i3",
+                            "size": {
+                                "width": {
+                                    "magnitude": 3000000,
+                                    "unit": "EMU"
+                                },
+                                "height": {
+                                    "magnitude": 3000000,
+                                    "unit": "EMU"
+                                }
+                            },
+                            "transform": {
+                                "scaleX": 1.8288,
+                                "scaleY": 1.3716,
+                                "translateX": 685800,
+                                "translateY": 4343400,
+                                "unit": "EMU"
+                            },
+                            "shape": {
+                                "shapeType": "TEXT_BOX",
+                                "shapeProperties": {
+                                    "shapeBackgroundFill": {
+                                        "propertyState": "INHERIT"
+                                    },
+                                    "outline": {
+                                        "propertyState": "INHERIT"
+                                    },
+                                    "shadow": {
+                                        "propertyState": "INHERIT"
+                                    }
+                                },
+                                "placeholder": {
+                                    "type": "BODY",
+                                    "index": 1,
+                                    "parentObjectId": "n:text"
+                                }
+                            }
+                        }
+                    ],
+                    "pageProperties": {
+                        "pageBackgroundFill": {
+                            "propertyState": "INHERIT"
+                        }
+                    },
+                    "notesProperties": {
+                        "speakerNotesObjectId": "i3"
+                    }
+                }
+            },
+            "pageProperties": {
+                "pageBackgroundFill": {
+                    "propertyState": "INHERIT"
+                }
+            }
+        },
+        {
+            "objectId": "g5f40953d50_0_0",
+            "pageElements": [
+                {
+                    "objectId": "g5f40953d50_0_1",
+                    "size": {
+                        "width": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        },
+                        "height": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        }
+                    },
+                    "transform": {
+                        "scaleX": 2.8402,
+                        "scaleY": 0.1909,
+                        "translateX": 311700,
+                        "translateY": 445025,
+                        "unit": "EMU"
+                    },
+                    "shape": {
+                        "shapeType": "TEXT_BOX",
+                        "text": {
+                            "textElements": [
+                                {
+                                    "endIndex": 10,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        }
+                                    }
+                                },
+                                {
+                                    "endIndex": 10,
+                                    "textRun": {
+                                        "content": "Dr. Seuss\n",
+                                        "style": {}
+                                    }
+                                }
+                            ]
+                        },
+                        "shapeProperties": {
+                            "shapeBackgroundFill": {
+                                "propertyState": "INHERIT"
+                            },
+                            "outline": {
+                                "propertyState": "INHERIT"
+                            },
+                            "shadow": {
+                                "propertyState": "INHERIT"
+                            }
+                        },
+                        "placeholder": {
+                            "type": "TITLE",
+                            "parentObjectId": "p4_i0"
+                        }
+                    }
+                },
+                {
+                    "objectId": "g5f40953d50_0_2",
+                    "size": {
+                        "width": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        },
+                        "height": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        }
+                    },
+                    "transform": {
+                        "scaleX": 2.8402,
+                        "scaleY": 1.1388,
+                        "translateX": 311700,
+                        "translateY": 1152475,
+                        "unit": "EMU"
+                    },
+                    "shape": {
+                        "shapeType": "TEXT_BOX",
+                        "text": {
+                            "textElements": [
+                                {
+                                    "endIndex": 25,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "indentStart": {
+                                                "unit": "PT"
+                                            },
+                                            "indentFirstLine": {
+                                                "unit": "PT"
+                                            },
+                                            "direction": "LEFT_TO_RIGHT"
+                                        }
+                                    }
+                                },
+                                {
+                                    "endIndex": 25,
+                                    "textRun": {
+                                        "content": "Here is a bulleted list!\n",
+                                        "style": {}
+                                    }
+                                },
+                                {
+                                    "startIndex": 25,
+                                    "endIndex": 34,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "indentStart": {
+                                                "magnitude": 36,
+                                                "unit": "PT"
+                                            },
+                                            "indentFirstLine": {
+                                                "magnitude": 18,
+                                                "unit": "PT"
+                                            },
+                                            "direction": "LEFT_TO_RIGHT",
+                                            "spacingMode": "COLLAPSE_LISTS"
+                                        },
+                                        "bullet": {
+                                            "listId": "kix.wifbmqnyqu4p",
+                                            "glyph": "●",
+                                            "bulletStyle": {
+                                                "underline": false
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 25,
+                                    "endIndex": 34,
+                                    "textRun": {
+                                        "content": "One fish\n",
+                                        "style": {}
+                                    }
+                                },
+                                {
+                                    "startIndex": 34,
+                                    "endIndex": 43,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "indentStart": {
+                                                "magnitude": 36,
+                                                "unit": "PT"
+                                            },
+                                            "indentFirstLine": {
+                                                "magnitude": 18,
+                                                "unit": "PT"
+                                            },
+                                            "direction": "LEFT_TO_RIGHT",
+                                            "spacingMode": "COLLAPSE_LISTS"
+                                        },
+                                        "bullet": {
+                                            "listId": "kix.wifbmqnyqu4p",
+                                            "glyph": "●",
+                                            "bulletStyle": {
+                                                "underline": false
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 34,
+                                    "endIndex": 43,
+                                    "textRun": {
+                                        "content": "Two fish\n",
+                                        "style": {}
+                                    }
+                                },
+                                {
+                                    "startIndex": 43,
+                                    "endIndex": 52,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "indentStart": {
+                                                "magnitude": 36,
+                                                "unit": "PT"
+                                            },
+                                            "indentFirstLine": {
+                                                "magnitude": 18,
+                                                "unit": "PT"
+                                            },
+                                            "direction": "LEFT_TO_RIGHT",
+                                            "spacingMode": "COLLAPSE_LISTS"
+                                        },
+                                        "bullet": {
+                                            "listId": "kix.wifbmqnyqu4p",
+                                            "glyph": "●",
+                                            "bulletStyle": {
+                                                "underline": false
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 43,
+                                    "endIndex": 52,
+                                    "textRun": {
+                                        "content": "Red fish\n",
+                                        "style": {}
+                                    }
+                                },
+                                {
+                                    "startIndex": 52,
+                                    "endIndex": 62,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "indentStart": {
+                                                "magnitude": 36,
+                                                "unit": "PT"
+                                            },
+                                            "indentFirstLine": {
+                                                "magnitude": 18,
+                                                "unit": "PT"
+                                            },
+                                            "direction": "LEFT_TO_RIGHT",
+                                            "spacingMode": "COLLAPSE_LISTS"
+                                        },
+                                        "bullet": {
+                                            "listId": "kix.wifbmqnyqu4p",
+                                            "glyph": "●",
+                                            "bulletStyle": {
+                                                "underline": false
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 52,
+                                    "endIndex": 62,
+                                    "textRun": {
+                                        "content": "Blue fish\n",
+                                        "style": {}
+                                    }
+                                }
+                            ],
+                            "lists": {
+                                "kix.wifbmqnyqu4p": {
+                                    "listId": "kix.wifbmqnyqu4p",
+                                    "nestingLevel": {
+                                        "0": {
+                                            "bulletStyle": {
+                                                "underline": false
+                                            }
+                                        },
+                                        "1": {
+                                            "bulletStyle": {
+                                                "underline": false
+                                            }
+                                        },
+                                        "2": {
+                                            "bulletStyle": {
+                                                "underline": false
+                                            }
+                                        },
+                                        "3": {
+                                            "bulletStyle": {
+                                                "underline": false
+                                            }
+                                        },
+                                        "4": {
+                                            "bulletStyle": {
+                                                "underline": false
+                                            }
+                                        },
+                                        "5": {
+                                            "bulletStyle": {
+                                                "underline": false
+                                            }
+                                        },
+                                        "6": {
+                                            "bulletStyle": {
+                                                "underline": false
+                                            }
+                                        },
+                                        "7": {
+                                            "bulletStyle": {
+                                                "underline": false
+                                            }
+                                        },
+                                        "8": {
+                                            "bulletStyle": {
+                                                "underline": false
+                                            }
+                                        }
+                                    }
+                                },
+                                "kix.yuy8atv38lqp": {
+                                    "listId": "kix.yuy8atv38lqp",
+                                    "nestingLevel": {
+                                        "0": {
+                                            "bulletStyle": {
+                                                "underline": false
+                                            }
+                                        },
+                                        "1": {
+                                            "bulletStyle": {
+                                                "underline": false
+                                            }
+                                        },
+                                        "2": {
+                                            "bulletStyle": {
+                                                "underline": false
+                                            }
+                                        },
+                                        "3": {
+                                            "bulletStyle": {
+                                                "underline": false
+                                            }
+                                        },
+                                        "4": {
+                                            "bulletStyle": {
+                                                "underline": false
+                                            }
+                                        },
+                                        "5": {
+                                            "bulletStyle": {
+                                                "underline": false
+                                            }
+                                        },
+                                        "6": {
+                                            "bulletStyle": {
+                                                "underline": false
+                                            }
+                                        },
+                                        "7": {
+                                            "bulletStyle": {
+                                                "underline": false
+                                            }
+                                        },
+                                        "8": {
+                                            "bulletStyle": {
+                                                "underline": false
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        },
+                        "shapeProperties": {
+                            "shapeBackgroundFill": {
+                                "propertyState": "INHERIT"
+                            },
+                            "outline": {
+                                "propertyState": "INHERIT"
+                            },
+                            "shadow": {
+                                "propertyState": "INHERIT"
+                            }
+                        },
+                        "placeholder": {
+                            "type": "BODY",
+                            "parentObjectId": "p4_i1"
+                        }
+                    }
+                }
+            ],
+            "slideProperties": {
+                "layoutObjectId": "p4",
+                "masterObjectId": "simple-light-2",
+                "notesPage": {
+                    "objectId": "g5f40953d50_0_0:notes",
+                    "pageType": "NOTES",
+                    "pageElements": [
+                        {
+                            "objectId": "g5f40953d50_0_3",
+                            "size": {
+                                "width": {
+                                    "magnitude": 3000000,
+                                    "unit": "EMU"
+                                },
+                                "height": {
+                                    "magnitude": 3000000,
+                                    "unit": "EMU"
+                                }
+                            },
+                            "transform": {
+                                "scaleX": 2.032,
+                                "scaleY": 1.143,
+                                "translateX": 381300,
+                                "translateY": 685800,
+                                "unit": "EMU"
+                            },
+                            "shape": {
+                                "shapeProperties": {
+                                    "outline": {
+                                        "propertyState": "INHERIT"
+                                    }
+                                },
+                                "placeholder": {
+                                    "type": "SLIDE_IMAGE",
+                                    "parentObjectId": "n:slide"
+                                }
+                            }
+                        },
+                        {
+                            "objectId": "g5f40953d50_0_4",
+                            "size": {
+                                "width": {
+                                    "magnitude": 3000000,
+                                    "unit": "EMU"
+                                },
+                                "height": {
+                                    "magnitude": 3000000,
+                                    "unit": "EMU"
+                                }
+                            },
+                            "transform": {
+                                "scaleX": 1.8288,
+                                "scaleY": 1.3716,
+                                "translateX": 685800,
+                                "translateY": 4343400,
+                                "unit": "EMU"
+                            },
+                            "shape": {
+                                "shapeType": "TEXT_BOX",
+                                "shapeProperties": {
+                                    "shapeBackgroundFill": {
+                                        "propertyState": "INHERIT"
+                                    },
+                                    "outline": {
+                                        "propertyState": "INHERIT"
+                                    },
+                                    "shadow": {
+                                        "propertyState": "INHERIT"
+                                    }
+                                },
+                                "placeholder": {
+                                    "type": "BODY",
+                                    "index": 1,
+                                    "parentObjectId": "n:text"
+                                }
+                            }
+                        }
+                    ],
+                    "pageProperties": {
+                        "pageBackgroundFill": {
+                            "propertyState": "INHERIT"
+                        }
+                    },
+                    "notesProperties": {
+                        "speakerNotesObjectId": "g5f40953d50_0_4"
+                    }
+                }
+            },
+            "pageProperties": {
+                "pageBackgroundFill": {
+                    "propertyState": "INHERIT"
+                }
+            }
+        }
+    ],
+    "title": "THIS IS MY FIRST DASH PRESENTATION",
+    "masters": [
+        {
+            "objectId": "simple-light-2",
+            "pageType": "MASTER",
+            "pageElements": [
+                {
+                    "objectId": "p1_i0",
+                    "size": {
+                        "width": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        },
+                        "height": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        }
+                    },
+                    "transform": {
+                        "scaleX": 2.8402,
+                        "scaleY": 0.1909,
+                        "translateX": 311700,
+                        "translateY": 445025,
+                        "unit": "EMU"
+                    },
+                    "shape": {
+                        "shapeType": "TEXT_BOX",
+                        "text": {
+                            "textElements": [
+                                {
+                                    "endIndex": 1,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "lineSpacing": 100,
+                                            "alignment": "START",
+                                            "indentStart": {
+                                                "unit": "PT"
+                                            },
+                                            "indentEnd": {
+                                                "unit": "PT"
+                                            },
+                                            "spaceAbove": {
+                                                "unit": "PT"
+                                            },
+                                            "spaceBelow": {
+                                                "unit": "PT"
+                                            },
+                                            "indentFirstLine": {
+                                                "unit": "PT"
+                                            },
+                                            "direction": "LEFT_TO_RIGHT",
+                                            "spacingMode": "NEVER_COLLAPSE"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "endIndex": 1,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "backgroundColor": {},
+                                            "foregroundColor": {
+                                                "opaqueColor": {
+                                                    "themeColor": "DARK1"
+                                                }
+                                            },
+                                            "bold": false,
+                                            "italic": false,
+                                            "fontFamily": "Arial",
+                                            "fontSize": {
+                                                "magnitude": 28,
+                                                "unit": "PT"
+                                            },
+                                            "baselineOffset": "NONE",
+                                            "smallCaps": false,
+                                            "strikethrough": false,
+                                            "underline": false,
+                                            "weightedFontFamily": {
+                                                "fontFamily": "Arial",
+                                                "weight": 400
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 1,
+                                    "endIndex": 2,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "lineSpacing": 100,
+                                            "alignment": "START",
+                                            "indentStart": {
+                                                "unit": "PT"
+                                            },
+                                            "indentEnd": {
+                                                "unit": "PT"
+                                            },
+                                            "spaceAbove": {
+                                                "unit": "PT"
+                                            },
+                                            "spaceBelow": {
+                                                "unit": "PT"
+                                            },
+                                            "indentFirstLine": {
+                                                "unit": "PT"
+                                            },
+                                            "direction": "LEFT_TO_RIGHT",
+                                            "spacingMode": "NEVER_COLLAPSE"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 1,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 1,
+                                    "endIndex": 2,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "backgroundColor": {},
+                                            "foregroundColor": {
+                                                "opaqueColor": {
+                                                    "themeColor": "DARK1"
+                                                }
+                                            },
+                                            "bold": false,
+                                            "italic": false,
+                                            "fontFamily": "Arial",
+                                            "fontSize": {
+                                                "magnitude": 28,
+                                                "unit": "PT"
+                                            },
+                                            "baselineOffset": "NONE",
+                                            "smallCaps": false,
+                                            "strikethrough": false,
+                                            "underline": false,
+                                            "weightedFontFamily": {
+                                                "fontFamily": "Arial",
+                                                "weight": 400
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 2,
+                                    "endIndex": 3,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "lineSpacing": 100,
+                                            "alignment": "START",
+                                            "indentStart": {
+                                                "unit": "PT"
+                                            },
+                                            "indentEnd": {
+                                                "unit": "PT"
+                                            },
+                                            "spaceAbove": {
+                                                "unit": "PT"
+                                            },
+                                            "spaceBelow": {
+                                                "unit": "PT"
+                                            },
+                                            "indentFirstLine": {
+                                                "unit": "PT"
+                                            },
+                                            "direction": "LEFT_TO_RIGHT",
+                                            "spacingMode": "NEVER_COLLAPSE"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 2,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 2,
+                                    "endIndex": 3,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "backgroundColor": {},
+                                            "foregroundColor": {
+                                                "opaqueColor": {
+                                                    "themeColor": "DARK1"
+                                                }
+                                            },
+                                            "bold": false,
+                                            "italic": false,
+                                            "fontFamily": "Arial",
+                                            "fontSize": {
+                                                "magnitude": 28,
+                                                "unit": "PT"
+                                            },
+                                            "baselineOffset": "NONE",
+                                            "smallCaps": false,
+                                            "strikethrough": false,
+                                            "underline": false,
+                                            "weightedFontFamily": {
+                                                "fontFamily": "Arial",
+                                                "weight": 400
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 3,
+                                    "endIndex": 4,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "lineSpacing": 100,
+                                            "alignment": "START",
+                                            "indentStart": {
+                                                "unit": "PT"
+                                            },
+                                            "indentEnd": {
+                                                "unit": "PT"
+                                            },
+                                            "spaceAbove": {
+                                                "unit": "PT"
+                                            },
+                                            "spaceBelow": {
+                                                "unit": "PT"
+                                            },
+                                            "indentFirstLine": {
+                                                "unit": "PT"
+                                            },
+                                            "direction": "LEFT_TO_RIGHT",
+                                            "spacingMode": "NEVER_COLLAPSE"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 3,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 3,
+                                    "endIndex": 4,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "backgroundColor": {},
+                                            "foregroundColor": {
+                                                "opaqueColor": {
+                                                    "themeColor": "DARK1"
+                                                }
+                                            },
+                                            "bold": false,
+                                            "italic": false,
+                                            "fontFamily": "Arial",
+                                            "fontSize": {
+                                                "magnitude": 28,
+                                                "unit": "PT"
+                                            },
+                                            "baselineOffset": "NONE",
+                                            "smallCaps": false,
+                                            "strikethrough": false,
+                                            "underline": false,
+                                            "weightedFontFamily": {
+                                                "fontFamily": "Arial",
+                                                "weight": 400
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 4,
+                                    "endIndex": 5,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "lineSpacing": 100,
+                                            "alignment": "START",
+                                            "indentStart": {
+                                                "unit": "PT"
+                                            },
+                                            "indentEnd": {
+                                                "unit": "PT"
+                                            },
+                                            "spaceAbove": {
+                                                "unit": "PT"
+                                            },
+                                            "spaceBelow": {
+                                                "unit": "PT"
+                                            },
+                                            "indentFirstLine": {
+                                                "unit": "PT"
+                                            },
+                                            "direction": "LEFT_TO_RIGHT",
+                                            "spacingMode": "NEVER_COLLAPSE"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 4,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 4,
+                                    "endIndex": 5,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "backgroundColor": {},
+                                            "foregroundColor": {
+                                                "opaqueColor": {
+                                                    "themeColor": "DARK1"
+                                                }
+                                            },
+                                            "bold": false,
+                                            "italic": false,
+                                            "fontFamily": "Arial",
+                                            "fontSize": {
+                                                "magnitude": 28,
+                                                "unit": "PT"
+                                            },
+                                            "baselineOffset": "NONE",
+                                            "smallCaps": false,
+                                            "strikethrough": false,
+                                            "underline": false,
+                                            "weightedFontFamily": {
+                                                "fontFamily": "Arial",
+                                                "weight": 400
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 5,
+                                    "endIndex": 6,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "lineSpacing": 100,
+                                            "alignment": "START",
+                                            "indentStart": {
+                                                "unit": "PT"
+                                            },
+                                            "indentEnd": {
+                                                "unit": "PT"
+                                            },
+                                            "spaceAbove": {
+                                                "unit": "PT"
+                                            },
+                                            "spaceBelow": {
+                                                "unit": "PT"
+                                            },
+                                            "indentFirstLine": {
+                                                "unit": "PT"
+                                            },
+                                            "direction": "LEFT_TO_RIGHT",
+                                            "spacingMode": "NEVER_COLLAPSE"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 5,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 5,
+                                    "endIndex": 6,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "backgroundColor": {},
+                                            "foregroundColor": {
+                                                "opaqueColor": {
+                                                    "themeColor": "DARK1"
+                                                }
+                                            },
+                                            "bold": false,
+                                            "italic": false,
+                                            "fontFamily": "Arial",
+                                            "fontSize": {
+                                                "magnitude": 28,
+                                                "unit": "PT"
+                                            },
+                                            "baselineOffset": "NONE",
+                                            "smallCaps": false,
+                                            "strikethrough": false,
+                                            "underline": false,
+                                            "weightedFontFamily": {
+                                                "fontFamily": "Arial",
+                                                "weight": 400
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 6,
+                                    "endIndex": 7,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "lineSpacing": 100,
+                                            "alignment": "START",
+                                            "indentStart": {
+                                                "unit": "PT"
+                                            },
+                                            "indentEnd": {
+                                                "unit": "PT"
+                                            },
+                                            "spaceAbove": {
+                                                "unit": "PT"
+                                            },
+                                            "spaceBelow": {
+                                                "unit": "PT"
+                                            },
+                                            "indentFirstLine": {
+                                                "unit": "PT"
+                                            },
+                                            "direction": "LEFT_TO_RIGHT",
+                                            "spacingMode": "NEVER_COLLAPSE"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 6,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 6,
+                                    "endIndex": 7,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "backgroundColor": {},
+                                            "foregroundColor": {
+                                                "opaqueColor": {
+                                                    "themeColor": "DARK1"
+                                                }
+                                            },
+                                            "bold": false,
+                                            "italic": false,
+                                            "fontFamily": "Arial",
+                                            "fontSize": {
+                                                "magnitude": 28,
+                                                "unit": "PT"
+                                            },
+                                            "baselineOffset": "NONE",
+                                            "smallCaps": false,
+                                            "strikethrough": false,
+                                            "underline": false,
+                                            "weightedFontFamily": {
+                                                "fontFamily": "Arial",
+                                                "weight": 400
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 7,
+                                    "endIndex": 8,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "lineSpacing": 100,
+                                            "alignment": "START",
+                                            "indentStart": {
+                                                "unit": "PT"
+                                            },
+                                            "indentEnd": {
+                                                "unit": "PT"
+                                            },
+                                            "spaceAbove": {
+                                                "unit": "PT"
+                                            },
+                                            "spaceBelow": {
+                                                "unit": "PT"
+                                            },
+                                            "indentFirstLine": {
+                                                "unit": "PT"
+                                            },
+                                            "direction": "LEFT_TO_RIGHT",
+                                            "spacingMode": "NEVER_COLLAPSE"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 7,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 7,
+                                    "endIndex": 8,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "backgroundColor": {},
+                                            "foregroundColor": {
+                                                "opaqueColor": {
+                                                    "themeColor": "DARK1"
+                                                }
+                                            },
+                                            "bold": false,
+                                            "italic": false,
+                                            "fontFamily": "Arial",
+                                            "fontSize": {
+                                                "magnitude": 28,
+                                                "unit": "PT"
+                                            },
+                                            "baselineOffset": "NONE",
+                                            "smallCaps": false,
+                                            "strikethrough": false,
+                                            "underline": false,
+                                            "weightedFontFamily": {
+                                                "fontFamily": "Arial",
+                                                "weight": 400
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 8,
+                                    "endIndex": 9,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "lineSpacing": 100,
+                                            "alignment": "START",
+                                            "indentStart": {
+                                                "unit": "PT"
+                                            },
+                                            "indentEnd": {
+                                                "unit": "PT"
+                                            },
+                                            "spaceAbove": {
+                                                "unit": "PT"
+                                            },
+                                            "spaceBelow": {
+                                                "unit": "PT"
+                                            },
+                                            "indentFirstLine": {
+                                                "unit": "PT"
+                                            },
+                                            "direction": "LEFT_TO_RIGHT",
+                                            "spacingMode": "NEVER_COLLAPSE"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 8,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 8,
+                                    "endIndex": 9,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "backgroundColor": {},
+                                            "foregroundColor": {
+                                                "opaqueColor": {
+                                                    "themeColor": "DARK1"
+                                                }
+                                            },
+                                            "bold": false,
+                                            "italic": false,
+                                            "fontFamily": "Arial",
+                                            "fontSize": {
+                                                "magnitude": 28,
+                                                "unit": "PT"
+                                            },
+                                            "baselineOffset": "NONE",
+                                            "smallCaps": false,
+                                            "strikethrough": false,
+                                            "underline": false,
+                                            "weightedFontFamily": {
+                                                "fontFamily": "Arial",
+                                                "weight": 400
+                                            }
+                                        }
+                                    }
+                                }
+                            ],
+                            "lists": {
+                                "bodyPlaceholderListEntity": {
+                                    "listId": "bodyPlaceholderListEntity",
+                                    "nestingLevel": {
+                                        "0": {
+                                            "bulletStyle": {
+                                                "backgroundColor": {},
+                                                "foregroundColor": {
+                                                    "opaqueColor": {
+                                                        "themeColor": "DARK1"
+                                                    }
+                                                },
+                                                "bold": false,
+                                                "italic": false,
+                                                "fontFamily": "Arial",
+                                                "fontSize": {
+                                                    "magnitude": 28,
+                                                    "unit": "PT"
+                                                },
+                                                "baselineOffset": "NONE",
+                                                "smallCaps": false,
+                                                "strikethrough": false,
+                                                "underline": false,
+                                                "weightedFontFamily": {
+                                                    "fontFamily": "Arial",
+                                                    "weight": 400
+                                                }
+                                            }
+                                        },
+                                        "1": {
+                                            "bulletStyle": {
+                                                "backgroundColor": {},
+                                                "foregroundColor": {
+                                                    "opaqueColor": {
+                                                        "themeColor": "DARK1"
+                                                    }
+                                                },
+                                                "bold": false,
+                                                "italic": false,
+                                                "fontFamily": "Arial",
+                                                "fontSize": {
+                                                    "magnitude": 28,
+                                                    "unit": "PT"
+                                                },
+                                                "baselineOffset": "NONE",
+                                                "smallCaps": false,
+                                                "strikethrough": false,
+                                                "underline": false,
+                                                "weightedFontFamily": {
+                                                    "fontFamily": "Arial",
+                                                    "weight": 400
+                                                }
+                                            }
+                                        },
+                                        "2": {
+                                            "bulletStyle": {
+                                                "backgroundColor": {},
+                                                "foregroundColor": {
+                                                    "opaqueColor": {
+                                                        "themeColor": "DARK1"
+                                                    }
+                                                },
+                                                "bold": false,
+                                                "italic": false,
+                                                "fontFamily": "Arial",
+                                                "fontSize": {
+                                                    "magnitude": 28,
+                                                    "unit": "PT"
+                                                },
+                                                "baselineOffset": "NONE",
+                                                "smallCaps": false,
+                                                "strikethrough": false,
+                                                "underline": false,
+                                                "weightedFontFamily": {
+                                                    "fontFamily": "Arial",
+                                                    "weight": 400
+                                                }
+                                            }
+                                        },
+                                        "3": {
+                                            "bulletStyle": {
+                                                "backgroundColor": {},
+                                                "foregroundColor": {
+                                                    "opaqueColor": {
+                                                        "themeColor": "DARK1"
+                                                    }
+                                                },
+                                                "bold": false,
+                                                "italic": false,
+                                                "fontFamily": "Arial",
+                                                "fontSize": {
+                                                    "magnitude": 28,
+                                                    "unit": "PT"
+                                                },
+                                                "baselineOffset": "NONE",
+                                                "smallCaps": false,
+                                                "strikethrough": false,
+                                                "underline": false,
+                                                "weightedFontFamily": {
+                                                    "fontFamily": "Arial",
+                                                    "weight": 400
+                                                }
+                                            }
+                                        },
+                                        "4": {
+                                            "bulletStyle": {
+                                                "backgroundColor": {},
+                                                "foregroundColor": {
+                                                    "opaqueColor": {
+                                                        "themeColor": "DARK1"
+                                                    }
+                                                },
+                                                "bold": false,
+                                                "italic": false,
+                                                "fontFamily": "Arial",
+                                                "fontSize": {
+                                                    "magnitude": 28,
+                                                    "unit": "PT"
+                                                },
+                                                "baselineOffset": "NONE",
+                                                "smallCaps": false,
+                                                "strikethrough": false,
+                                                "underline": false,
+                                                "weightedFontFamily": {
+                                                    "fontFamily": "Arial",
+                                                    "weight": 400
+                                                }
+                                            }
+                                        },
+                                        "5": {
+                                            "bulletStyle": {
+                                                "backgroundColor": {},
+                                                "foregroundColor": {
+                                                    "opaqueColor": {
+                                                        "themeColor": "DARK1"
+                                                    }
+                                                },
+                                                "bold": false,
+                                                "italic": false,
+                                                "fontFamily": "Arial",
+                                                "fontSize": {
+                                                    "magnitude": 28,
+                                                    "unit": "PT"
+                                                },
+                                                "baselineOffset": "NONE",
+                                                "smallCaps": false,
+                                                "strikethrough": false,
+                                                "underline": false,
+                                                "weightedFontFamily": {
+                                                    "fontFamily": "Arial",
+                                                    "weight": 400
+                                                }
+                                            }
+                                        },
+                                        "6": {
+                                            "bulletStyle": {
+                                                "backgroundColor": {},
+                                                "foregroundColor": {
+                                                    "opaqueColor": {
+                                                        "themeColor": "DARK1"
+                                                    }
+                                                },
+                                                "bold": false,
+                                                "italic": false,
+                                                "fontFamily": "Arial",
+                                                "fontSize": {
+                                                    "magnitude": 28,
+                                                    "unit": "PT"
+                                                },
+                                                "baselineOffset": "NONE",
+                                                "smallCaps": false,
+                                                "strikethrough": false,
+                                                "underline": false,
+                                                "weightedFontFamily": {
+                                                    "fontFamily": "Arial",
+                                                    "weight": 400
+                                                }
+                                            }
+                                        },
+                                        "7": {
+                                            "bulletStyle": {
+                                                "backgroundColor": {},
+                                                "foregroundColor": {
+                                                    "opaqueColor": {
+                                                        "themeColor": "DARK1"
+                                                    }
+                                                },
+                                                "bold": false,
+                                                "italic": false,
+                                                "fontFamily": "Arial",
+                                                "fontSize": {
+                                                    "magnitude": 28,
+                                                    "unit": "PT"
+                                                },
+                                                "baselineOffset": "NONE",
+                                                "smallCaps": false,
+                                                "strikethrough": false,
+                                                "underline": false,
+                                                "weightedFontFamily": {
+                                                    "fontFamily": "Arial",
+                                                    "weight": 400
+                                                }
+                                            }
+                                        },
+                                        "8": {
+                                            "bulletStyle": {
+                                                "backgroundColor": {},
+                                                "foregroundColor": {
+                                                    "opaqueColor": {
+                                                        "themeColor": "DARK1"
+                                                    }
+                                                },
+                                                "bold": false,
+                                                "italic": false,
+                                                "fontFamily": "Arial",
+                                                "fontSize": {
+                                                    "magnitude": 28,
+                                                    "unit": "PT"
+                                                },
+                                                "baselineOffset": "NONE",
+                                                "smallCaps": false,
+                                                "strikethrough": false,
+                                                "underline": false,
+                                                "weightedFontFamily": {
+                                                    "fontFamily": "Arial",
+                                                    "weight": 400
+                                                }
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        },
+                        "shapeProperties": {
+                            "shapeBackgroundFill": {
+                                "propertyState": "NOT_RENDERED",
+                                "solidFill": {
+                                    "color": {
+                                        "rgbColor": {
+                                            "red": 1,
+                                            "green": 1,
+                                            "blue": 1
+                                        }
+                                    },
+                                    "alpha": 1
+                                }
+                            },
+                            "outline": {
+                                "outlineFill": {
+                                    "solidFill": {
+                                        "color": {
+                                            "rgbColor": {}
+                                        },
+                                        "alpha": 1
+                                    }
+                                },
+                                "weight": {
+                                    "magnitude": 9525,
+                                    "unit": "EMU"
+                                },
+                                "dashStyle": "SOLID",
+                                "propertyState": "NOT_RENDERED"
+                            },
+                            "shadow": {
+                                "type": "OUTER",
+                                "transform": {
+                                    "scaleX": 1,
+                                    "scaleY": 1,
+                                    "unit": "EMU"
+                                },
+                                "alignment": "BOTTOM_LEFT",
+                                "blurRadius": {
+                                    "unit": "EMU"
+                                },
+                                "color": {
+                                    "rgbColor": {}
+                                },
+                                "alpha": 1,
+                                "rotateWithShape": false,
+                                "propertyState": "NOT_RENDERED"
+                            },
+                            "contentAlignment": "TOP"
+                        },
+                        "placeholder": {
+                            "type": "TITLE"
+                        }
+                    }
+                },
+                {
+                    "objectId": "p1_i1",
+                    "size": {
+                        "width": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        },
+                        "height": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        }
+                    },
+                    "transform": {
+                        "scaleX": 2.8402,
+                        "scaleY": 1.1388,
+                        "translateX": 311700,
+                        "translateY": 1152475,
+                        "unit": "EMU"
+                    },
+                    "shape": {
+                        "shapeType": "TEXT_BOX",
+                        "text": {
+                            "textElements": [
+                                {
+                                    "endIndex": 1,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "lineSpacing": 115,
+                                            "alignment": "START",
+                                            "indentStart": {
+                                                "unit": "PT"
+                                            },
+                                            "indentEnd": {
+                                                "unit": "PT"
+                                            },
+                                            "spaceAbove": {
+                                                "unit": "PT"
+                                            },
+                                            "spaceBelow": {
+                                                "magnitude": 16,
+                                                "unit": "PT"
+                                            },
+                                            "indentFirstLine": {
+                                                "unit": "PT"
+                                            },
+                                            "direction": "LEFT_TO_RIGHT",
+                                            "spacingMode": "NEVER_COLLAPSE"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "glyph": "●",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "endIndex": 1,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "backgroundColor": {},
+                                            "foregroundColor": {
+                                                "opaqueColor": {
+                                                    "themeColor": "DARK2"
+                                                }
+                                            },
+                                            "bold": false,
+                                            "italic": false,
+                                            "fontFamily": "Arial",
+                                            "fontSize": {
+                                                "magnitude": 18,
+                                                "unit": "PT"
+                                            },
+                                            "baselineOffset": "NONE",
+                                            "smallCaps": false,
+                                            "strikethrough": false,
+                                            "underline": false,
+                                            "weightedFontFamily": {
+                                                "fontFamily": "Arial",
+                                                "weight": 400
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 1,
+                                    "endIndex": 2,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "lineSpacing": 115,
+                                            "alignment": "START",
+                                            "indentStart": {
+                                                "unit": "PT"
+                                            },
+                                            "indentEnd": {
+                                                "unit": "PT"
+                                            },
+                                            "spaceAbove": {
+                                                "unit": "PT"
+                                            },
+                                            "spaceBelow": {
+                                                "magnitude": 16,
+                                                "unit": "PT"
+                                            },
+                                            "indentFirstLine": {
+                                                "unit": "PT"
+                                            },
+                                            "direction": "LEFT_TO_RIGHT",
+                                            "spacingMode": "NEVER_COLLAPSE"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 1,
+                                            "glyph": "○",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 1,
+                                    "endIndex": 2,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "backgroundColor": {},
+                                            "foregroundColor": {
+                                                "opaqueColor": {
+                                                    "themeColor": "DARK2"
+                                                }
+                                            },
+                                            "bold": false,
+                                            "italic": false,
+                                            "fontFamily": "Arial",
+                                            "fontSize": {
+                                                "magnitude": 14,
+                                                "unit": "PT"
+                                            },
+                                            "baselineOffset": "NONE",
+                                            "smallCaps": false,
+                                            "strikethrough": false,
+                                            "underline": false,
+                                            "weightedFontFamily": {
+                                                "fontFamily": "Arial",
+                                                "weight": 400
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 2,
+                                    "endIndex": 3,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "lineSpacing": 115,
+                                            "alignment": "START",
+                                            "indentStart": {
+                                                "unit": "PT"
+                                            },
+                                            "indentEnd": {
+                                                "unit": "PT"
+                                            },
+                                            "spaceAbove": {
+                                                "unit": "PT"
+                                            },
+                                            "spaceBelow": {
+                                                "magnitude": 16,
+                                                "unit": "PT"
+                                            },
+                                            "indentFirstLine": {
+                                                "unit": "PT"
+                                            },
+                                            "direction": "LEFT_TO_RIGHT",
+                                            "spacingMode": "NEVER_COLLAPSE"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 2,
+                                            "glyph": "■",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 2,
+                                    "endIndex": 3,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "backgroundColor": {},
+                                            "foregroundColor": {
+                                                "opaqueColor": {
+                                                    "themeColor": "DARK2"
+                                                }
+                                            },
+                                            "bold": false,
+                                            "italic": false,
+                                            "fontFamily": "Arial",
+                                            "fontSize": {
+                                                "magnitude": 14,
+                                                "unit": "PT"
+                                            },
+                                            "baselineOffset": "NONE",
+                                            "smallCaps": false,
+                                            "strikethrough": false,
+                                            "underline": false,
+                                            "weightedFontFamily": {
+                                                "fontFamily": "Arial",
+                                                "weight": 400
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 3,
+                                    "endIndex": 4,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "lineSpacing": 115,
+                                            "alignment": "START",
+                                            "indentStart": {
+                                                "unit": "PT"
+                                            },
+                                            "indentEnd": {
+                                                "unit": "PT"
+                                            },
+                                            "spaceAbove": {
+                                                "unit": "PT"
+                                            },
+                                            "spaceBelow": {
+                                                "magnitude": 16,
+                                                "unit": "PT"
+                                            },
+                                            "indentFirstLine": {
+                                                "unit": "PT"
+                                            },
+                                            "direction": "LEFT_TO_RIGHT",
+                                            "spacingMode": "NEVER_COLLAPSE"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 3,
+                                            "glyph": "●",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 3,
+                                    "endIndex": 4,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "backgroundColor": {},
+                                            "foregroundColor": {
+                                                "opaqueColor": {
+                                                    "themeColor": "DARK2"
+                                                }
+                                            },
+                                            "bold": false,
+                                            "italic": false,
+                                            "fontFamily": "Arial",
+                                            "fontSize": {
+                                                "magnitude": 14,
+                                                "unit": "PT"
+                                            },
+                                            "baselineOffset": "NONE",
+                                            "smallCaps": false,
+                                            "strikethrough": false,
+                                            "underline": false,
+                                            "weightedFontFamily": {
+                                                "fontFamily": "Arial",
+                                                "weight": 400
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 4,
+                                    "endIndex": 5,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "lineSpacing": 115,
+                                            "alignment": "START",
+                                            "indentStart": {
+                                                "unit": "PT"
+                                            },
+                                            "indentEnd": {
+                                                "unit": "PT"
+                                            },
+                                            "spaceAbove": {
+                                                "unit": "PT"
+                                            },
+                                            "spaceBelow": {
+                                                "magnitude": 16,
+                                                "unit": "PT"
+                                            },
+                                            "indentFirstLine": {
+                                                "unit": "PT"
+                                            },
+                                            "direction": "LEFT_TO_RIGHT",
+                                            "spacingMode": "NEVER_COLLAPSE"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 4,
+                                            "glyph": "○",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 4,
+                                    "endIndex": 5,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "backgroundColor": {},
+                                            "foregroundColor": {
+                                                "opaqueColor": {
+                                                    "themeColor": "DARK2"
+                                                }
+                                            },
+                                            "bold": false,
+                                            "italic": false,
+                                            "fontFamily": "Arial",
+                                            "fontSize": {
+                                                "magnitude": 14,
+                                                "unit": "PT"
+                                            },
+                                            "baselineOffset": "NONE",
+                                            "smallCaps": false,
+                                            "strikethrough": false,
+                                            "underline": false,
+                                            "weightedFontFamily": {
+                                                "fontFamily": "Arial",
+                                                "weight": 400
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 5,
+                                    "endIndex": 6,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "lineSpacing": 115,
+                                            "alignment": "START",
+                                            "indentStart": {
+                                                "unit": "PT"
+                                            },
+                                            "indentEnd": {
+                                                "unit": "PT"
+                                            },
+                                            "spaceAbove": {
+                                                "unit": "PT"
+                                            },
+                                            "spaceBelow": {
+                                                "magnitude": 16,
+                                                "unit": "PT"
+                                            },
+                                            "indentFirstLine": {
+                                                "unit": "PT"
+                                            },
+                                            "direction": "LEFT_TO_RIGHT",
+                                            "spacingMode": "NEVER_COLLAPSE"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 5,
+                                            "glyph": "■",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 5,
+                                    "endIndex": 6,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "backgroundColor": {},
+                                            "foregroundColor": {
+                                                "opaqueColor": {
+                                                    "themeColor": "DARK2"
+                                                }
+                                            },
+                                            "bold": false,
+                                            "italic": false,
+                                            "fontFamily": "Arial",
+                                            "fontSize": {
+                                                "magnitude": 14,
+                                                "unit": "PT"
+                                            },
+                                            "baselineOffset": "NONE",
+                                            "smallCaps": false,
+                                            "strikethrough": false,
+                                            "underline": false,
+                                            "weightedFontFamily": {
+                                                "fontFamily": "Arial",
+                                                "weight": 400
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 6,
+                                    "endIndex": 7,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "lineSpacing": 115,
+                                            "alignment": "START",
+                                            "indentStart": {
+                                                "unit": "PT"
+                                            },
+                                            "indentEnd": {
+                                                "unit": "PT"
+                                            },
+                                            "spaceAbove": {
+                                                "unit": "PT"
+                                            },
+                                            "spaceBelow": {
+                                                "magnitude": 16,
+                                                "unit": "PT"
+                                            },
+                                            "indentFirstLine": {
+                                                "unit": "PT"
+                                            },
+                                            "direction": "LEFT_TO_RIGHT",
+                                            "spacingMode": "NEVER_COLLAPSE"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 6,
+                                            "glyph": "●",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 6,
+                                    "endIndex": 7,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "backgroundColor": {},
+                                            "foregroundColor": {
+                                                "opaqueColor": {
+                                                    "themeColor": "DARK2"
+                                                }
+                                            },
+                                            "bold": false,
+                                            "italic": false,
+                                            "fontFamily": "Arial",
+                                            "fontSize": {
+                                                "magnitude": 14,
+                                                "unit": "PT"
+                                            },
+                                            "baselineOffset": "NONE",
+                                            "smallCaps": false,
+                                            "strikethrough": false,
+                                            "underline": false,
+                                            "weightedFontFamily": {
+                                                "fontFamily": "Arial",
+                                                "weight": 400
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 7,
+                                    "endIndex": 8,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "lineSpacing": 115,
+                                            "alignment": "START",
+                                            "indentStart": {
+                                                "unit": "PT"
+                                            },
+                                            "indentEnd": {
+                                                "unit": "PT"
+                                            },
+                                            "spaceAbove": {
+                                                "unit": "PT"
+                                            },
+                                            "spaceBelow": {
+                                                "magnitude": 16,
+                                                "unit": "PT"
+                                            },
+                                            "indentFirstLine": {
+                                                "unit": "PT"
+                                            },
+                                            "direction": "LEFT_TO_RIGHT",
+                                            "spacingMode": "NEVER_COLLAPSE"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 7,
+                                            "glyph": "○",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 7,
+                                    "endIndex": 8,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "backgroundColor": {},
+                                            "foregroundColor": {
+                                                "opaqueColor": {
+                                                    "themeColor": "DARK2"
+                                                }
+                                            },
+                                            "bold": false,
+                                            "italic": false,
+                                            "fontFamily": "Arial",
+                                            "fontSize": {
+                                                "magnitude": 14,
+                                                "unit": "PT"
+                                            },
+                                            "baselineOffset": "NONE",
+                                            "smallCaps": false,
+                                            "strikethrough": false,
+                                            "underline": false,
+                                            "weightedFontFamily": {
+                                                "fontFamily": "Arial",
+                                                "weight": 400
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 8,
+                                    "endIndex": 9,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "lineSpacing": 115,
+                                            "alignment": "START",
+                                            "indentStart": {
+                                                "unit": "PT"
+                                            },
+                                            "indentEnd": {
+                                                "unit": "PT"
+                                            },
+                                            "spaceAbove": {
+                                                "unit": "PT"
+                                            },
+                                            "spaceBelow": {
+                                                "magnitude": 16,
+                                                "unit": "PT"
+                                            },
+                                            "indentFirstLine": {
+                                                "unit": "PT"
+                                            },
+                                            "direction": "LEFT_TO_RIGHT",
+                                            "spacingMode": "NEVER_COLLAPSE"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 8,
+                                            "glyph": "■",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 8,
+                                    "endIndex": 9,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "backgroundColor": {},
+                                            "foregroundColor": {
+                                                "opaqueColor": {
+                                                    "themeColor": "DARK2"
+                                                }
+                                            },
+                                            "bold": false,
+                                            "italic": false,
+                                            "fontFamily": "Arial",
+                                            "fontSize": {
+                                                "magnitude": 14,
+                                                "unit": "PT"
+                                            },
+                                            "baselineOffset": "NONE",
+                                            "smallCaps": false,
+                                            "strikethrough": false,
+                                            "underline": false,
+                                            "weightedFontFamily": {
+                                                "fontFamily": "Arial",
+                                                "weight": 400
+                                            }
+                                        }
+                                    }
+                                }
+                            ],
+                            "lists": {
+                                "bodyPlaceholderListEntity": {
+                                    "listId": "bodyPlaceholderListEntity",
+                                    "nestingLevel": {
+                                        "0": {
+                                            "bulletStyle": {
+                                                "backgroundColor": {},
+                                                "foregroundColor": {
+                                                    "opaqueColor": {
+                                                        "themeColor": "DARK2"
+                                                    }
+                                                },
+                                                "bold": false,
+                                                "italic": false,
+                                                "fontFamily": "Arial",
+                                                "fontSize": {
+                                                    "magnitude": 18,
+                                                    "unit": "PT"
+                                                },
+                                                "baselineOffset": "NONE",
+                                                "smallCaps": false,
+                                                "strikethrough": false,
+                                                "underline": false,
+                                                "weightedFontFamily": {
+                                                    "fontFamily": "Arial",
+                                                    "weight": 400
+                                                }
+                                            }
+                                        },
+                                        "1": {
+                                            "bulletStyle": {
+                                                "backgroundColor": {},
+                                                "foregroundColor": {
+                                                    "opaqueColor": {
+                                                        "themeColor": "DARK2"
+                                                    }
+                                                },
+                                                "bold": false,
+                                                "italic": false,
+                                                "fontFamily": "Arial",
+                                                "fontSize": {
+                                                    "magnitude": 14,
+                                                    "unit": "PT"
+                                                },
+                                                "baselineOffset": "NONE",
+                                                "smallCaps": false,
+                                                "strikethrough": false,
+                                                "underline": false,
+                                                "weightedFontFamily": {
+                                                    "fontFamily": "Arial",
+                                                    "weight": 400
+                                                }
+                                            }
+                                        },
+                                        "2": {
+                                            "bulletStyle": {
+                                                "backgroundColor": {},
+                                                "foregroundColor": {
+                                                    "opaqueColor": {
+                                                        "themeColor": "DARK2"
+                                                    }
+                                                },
+                                                "bold": false,
+                                                "italic": false,
+                                                "fontFamily": "Arial",
+                                                "fontSize": {
+                                                    "magnitude": 14,
+                                                    "unit": "PT"
+                                                },
+                                                "baselineOffset": "NONE",
+                                                "smallCaps": false,
+                                                "strikethrough": false,
+                                                "underline": false,
+                                                "weightedFontFamily": {
+                                                    "fontFamily": "Arial",
+                                                    "weight": 400
+                                                }
+                                            }
+                                        },
+                                        "3": {
+                                            "bulletStyle": {
+                                                "backgroundColor": {},
+                                                "foregroundColor": {
+                                                    "opaqueColor": {
+                                                        "themeColor": "DARK2"
+                                                    }
+                                                },
+                                                "bold": false,
+                                                "italic": false,
+                                                "fontFamily": "Arial",
+                                                "fontSize": {
+                                                    "magnitude": 14,
+                                                    "unit": "PT"
+                                                },
+                                                "baselineOffset": "NONE",
+                                                "smallCaps": false,
+                                                "strikethrough": false,
+                                                "underline": false,
+                                                "weightedFontFamily": {
+                                                    "fontFamily": "Arial",
+                                                    "weight": 400
+                                                }
+                                            }
+                                        },
+                                        "4": {
+                                            "bulletStyle": {
+                                                "backgroundColor": {},
+                                                "foregroundColor": {
+                                                    "opaqueColor": {
+                                                        "themeColor": "DARK2"
+                                                    }
+                                                },
+                                                "bold": false,
+                                                "italic": false,
+                                                "fontFamily": "Arial",
+                                                "fontSize": {
+                                                    "magnitude": 14,
+                                                    "unit": "PT"
+                                                },
+                                                "baselineOffset": "NONE",
+                                                "smallCaps": false,
+                                                "strikethrough": false,
+                                                "underline": false,
+                                                "weightedFontFamily": {
+                                                    "fontFamily": "Arial",
+                                                    "weight": 400
+                                                }
+                                            }
+                                        },
+                                        "5": {
+                                            "bulletStyle": {
+                                                "backgroundColor": {},
+                                                "foregroundColor": {
+                                                    "opaqueColor": {
+                                                        "themeColor": "DARK2"
+                                                    }
+                                                },
+                                                "bold": false,
+                                                "italic": false,
+                                                "fontFamily": "Arial",
+                                                "fontSize": {
+                                                    "magnitude": 14,
+                                                    "unit": "PT"
+                                                },
+                                                "baselineOffset": "NONE",
+                                                "smallCaps": false,
+                                                "strikethrough": false,
+                                                "underline": false,
+                                                "weightedFontFamily": {
+                                                    "fontFamily": "Arial",
+                                                    "weight": 400
+                                                }
+                                            }
+                                        },
+                                        "6": {
+                                            "bulletStyle": {
+                                                "backgroundColor": {},
+                                                "foregroundColor": {
+                                                    "opaqueColor": {
+                                                        "themeColor": "DARK2"
+                                                    }
+                                                },
+                                                "bold": false,
+                                                "italic": false,
+                                                "fontFamily": "Arial",
+                                                "fontSize": {
+                                                    "magnitude": 14,
+                                                    "unit": "PT"
+                                                },
+                                                "baselineOffset": "NONE",
+                                                "smallCaps": false,
+                                                "strikethrough": false,
+                                                "underline": false,
+                                                "weightedFontFamily": {
+                                                    "fontFamily": "Arial",
+                                                    "weight": 400
+                                                }
+                                            }
+                                        },
+                                        "7": {
+                                            "bulletStyle": {
+                                                "backgroundColor": {},
+                                                "foregroundColor": {
+                                                    "opaqueColor": {
+                                                        "themeColor": "DARK2"
+                                                    }
+                                                },
+                                                "bold": false,
+                                                "italic": false,
+                                                "fontFamily": "Arial",
+                                                "fontSize": {
+                                                    "magnitude": 14,
+                                                    "unit": "PT"
+                                                },
+                                                "baselineOffset": "NONE",
+                                                "smallCaps": false,
+                                                "strikethrough": false,
+                                                "underline": false,
+                                                "weightedFontFamily": {
+                                                    "fontFamily": "Arial",
+                                                    "weight": 400
+                                                }
+                                            }
+                                        },
+                                        "8": {
+                                            "bulletStyle": {
+                                                "backgroundColor": {},
+                                                "foregroundColor": {
+                                                    "opaqueColor": {
+                                                        "themeColor": "DARK2"
+                                                    }
+                                                },
+                                                "bold": false,
+                                                "italic": false,
+                                                "fontFamily": "Arial",
+                                                "fontSize": {
+                                                    "magnitude": 14,
+                                                    "unit": "PT"
+                                                },
+                                                "baselineOffset": "NONE",
+                                                "smallCaps": false,
+                                                "strikethrough": false,
+                                                "underline": false,
+                                                "weightedFontFamily": {
+                                                    "fontFamily": "Arial",
+                                                    "weight": 400
+                                                }
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        },
+                        "shapeProperties": {
+                            "shapeBackgroundFill": {
+                                "propertyState": "NOT_RENDERED",
+                                "solidFill": {
+                                    "color": {
+                                        "rgbColor": {
+                                            "red": 1,
+                                            "green": 1,
+                                            "blue": 1
+                                        }
+                                    },
+                                    "alpha": 1
+                                }
+                            },
+                            "outline": {
+                                "outlineFill": {
+                                    "solidFill": {
+                                        "color": {
+                                            "rgbColor": {}
+                                        },
+                                        "alpha": 1
+                                    }
+                                },
+                                "weight": {
+                                    "magnitude": 9525,
+                                    "unit": "EMU"
+                                },
+                                "dashStyle": "SOLID",
+                                "propertyState": "NOT_RENDERED"
+                            },
+                            "shadow": {
+                                "type": "OUTER",
+                                "transform": {
+                                    "scaleX": 1,
+                                    "scaleY": 1,
+                                    "unit": "EMU"
+                                },
+                                "alignment": "BOTTOM_LEFT",
+                                "blurRadius": {
+                                    "unit": "EMU"
+                                },
+                                "color": {
+                                    "rgbColor": {}
+                                },
+                                "alpha": 1,
+                                "rotateWithShape": false,
+                                "propertyState": "NOT_RENDERED"
+                            },
+                            "contentAlignment": "TOP"
+                        },
+                        "placeholder": {
+                            "type": "BODY"
+                        }
+                    }
+                },
+                {
+                    "objectId": "p1_i2",
+                    "size": {
+                        "width": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        },
+                        "height": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        }
+                    },
+                    "transform": {
+                        "scaleX": 0.1829,
+                        "scaleY": 0.1312,
+                        "translateX": 8472457.8125,
+                        "translateY": 4663216.797499999,
+                        "unit": "EMU"
+                    },
+                    "shape": {
+                        "shapeType": "TEXT_BOX",
+                        "text": {
+                            "textElements": [
+                                {
+                                    "endIndex": 2,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "lineSpacing": 100,
+                                            "alignment": "END",
+                                            "indentStart": {
+                                                "unit": "PT"
+                                            },
+                                            "indentEnd": {
+                                                "unit": "PT"
+                                            },
+                                            "spaceAbove": {
+                                                "unit": "PT"
+                                            },
+                                            "spaceBelow": {
+                                                "unit": "PT"
+                                            },
+                                            "indentFirstLine": {
+                                                "unit": "PT"
+                                            },
+                                            "direction": "LEFT_TO_RIGHT",
+                                            "spacingMode": "NEVER_COLLAPSE"
+                                        }
+                                    }
+                                },
+                                {
+                                    "endIndex": 1,
+                                    "autoText": {
+                                        "type": "SLIDE_NUMBER",
+                                        "content": "#",
+                                        "style": {
+                                            "backgroundColor": {},
+                                            "foregroundColor": {
+                                                "opaqueColor": {
+                                                    "themeColor": "DARK2"
+                                                }
+                                            },
+                                            "bold": false,
+                                            "italic": false,
+                                            "fontFamily": "Arial",
+                                            "fontSize": {
+                                                "magnitude": 10,
+                                                "unit": "PT"
+                                            },
+                                            "baselineOffset": "NONE",
+                                            "smallCaps": false,
+                                            "strikethrough": false,
+                                            "underline": false,
+                                            "weightedFontFamily": {
+                                                "fontFamily": "Arial",
+                                                "weight": 400
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 1,
+                                    "endIndex": 2,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "backgroundColor": {},
+                                            "foregroundColor": {
+                                                "opaqueColor": {
+                                                    "themeColor": "DARK2"
+                                                }
+                                            },
+                                            "bold": false,
+                                            "italic": false,
+                                            "fontFamily": "Arial",
+                                            "fontSize": {
+                                                "magnitude": 10,
+                                                "unit": "PT"
+                                            },
+                                            "baselineOffset": "NONE",
+                                            "smallCaps": false,
+                                            "strikethrough": false,
+                                            "underline": false,
+                                            "weightedFontFamily": {
+                                                "fontFamily": "Arial",
+                                                "weight": 400
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        },
+                        "shapeProperties": {
+                            "shapeBackgroundFill": {
+                                "propertyState": "NOT_RENDERED",
+                                "solidFill": {
+                                    "color": {
+                                        "rgbColor": {
+                                            "red": 1,
+                                            "green": 1,
+                                            "blue": 1
+                                        }
+                                    },
+                                    "alpha": 1
+                                }
+                            },
+                            "outline": {
+                                "outlineFill": {
+                                    "solidFill": {
+                                        "color": {
+                                            "rgbColor": {}
+                                        },
+                                        "alpha": 1
+                                    }
+                                },
+                                "weight": {
+                                    "magnitude": 9525,
+                                    "unit": "EMU"
+                                },
+                                "dashStyle": "SOLID",
+                                "propertyState": "NOT_RENDERED"
+                            },
+                            "shadow": {
+                                "type": "OUTER",
+                                "transform": {
+                                    "scaleX": 1,
+                                    "scaleY": 1,
+                                    "unit": "EMU"
+                                },
+                                "alignment": "BOTTOM_LEFT",
+                                "blurRadius": {
+                                    "unit": "EMU"
+                                },
+                                "color": {
+                                    "rgbColor": {}
+                                },
+                                "alpha": 1,
+                                "rotateWithShape": false,
+                                "propertyState": "NOT_RENDERED"
+                            },
+                            "contentAlignment": "MIDDLE"
+                        },
+                        "placeholder": {
+                            "type": "SLIDE_NUMBER"
+                        }
+                    }
+                }
+            ],
+            "pageProperties": {
+                "pageBackgroundFill": {
+                    "solidFill": {
+                        "color": {
+                            "themeColor": "LIGHT1"
+                        },
+                        "alpha": 1
+                    }
+                },
+                "colorScheme": {
+                    "colors": [
+                        {
+                            "type": "DARK1",
+                            "color": {}
+                        },
+                        {
+                            "type": "LIGHT1",
+                            "color": {
+                                "red": 1,
+                                "green": 1,
+                                "blue": 1
+                            }
+                        },
+                        {
+                            "type": "DARK2",
+                            "color": {
+                                "red": 0.34901962,
+                                "green": 0.34901962,
+                                "blue": 0.34901962
+                            }
+                        },
+                        {
+                            "type": "LIGHT2",
+                            "color": {
+                                "red": 0.93333334,
+                                "green": 0.93333334,
+                                "blue": 0.93333334
+                            }
+                        },
+                        {
+                            "type": "ACCENT1",
+                            "color": {
+                                "red": 1,
+                                "green": 0.67058825,
+                                "blue": 0.2509804
+                            }
+                        },
+                        {
+                            "type": "ACCENT2",
+                            "color": {
+                                "red": 0.12941177,
+                                "green": 0.12941177,
+                                "blue": 0.12941177
+                            }
+                        },
+                        {
+                            "type": "ACCENT3",
+                            "color": {
+                                "red": 0.47058824,
+                                "green": 0.5647059,
+                                "blue": 0.6117647
+                            }
+                        },
+                        {
+                            "type": "ACCENT4",
+                            "color": {
+                                "red": 1,
+                                "green": 0.67058825,
+                                "blue": 0.2509804
+                            }
+                        },
+                        {
+                            "type": "ACCENT5",
+                            "color": {
+                                "green": 0.5921569,
+                                "blue": 0.654902
+                            }
+                        },
+                        {
+                            "type": "ACCENT6",
+                            "color": {
+                                "red": 0.93333334,
+                                "green": 1,
+                                "blue": 0.25490198
+                            }
+                        },
+                        {
+                            "type": "HYPERLINK",
+                            "color": {
+                                "green": 0.5921569,
+                                "blue": 0.654902
+                            }
+                        },
+                        {
+                            "type": "FOLLOWED_HYPERLINK",
+                            "color": {
+                                "green": 0.5921569,
+                                "blue": 0.654902
+                            }
+                        },
+                        {
+                            "type": "TEXT1",
+                            "color": {}
+                        },
+                        {
+                            "type": "BACKGROUND1",
+                            "color": {
+                                "red": 1,
+                                "green": 1,
+                                "blue": 1
+                            }
+                        },
+                        {
+                            "type": "TEXT2",
+                            "color": {
+                                "red": 0.93333334,
+                                "green": 0.93333334,
+                                "blue": 0.93333334
+                            }
+                        },
+                        {
+                            "type": "BACKGROUND2",
+                            "color": {
+                                "red": 0.34901962,
+                                "green": 0.34901962,
+                                "blue": 0.34901962
+                            }
+                        }
+                    ]
+                }
+            },
+            "masterProperties": {
+                "displayName": "Simple Light"
+            }
+        }
+    ],
+    "layouts": [
+        {
+            "objectId": "p2",
+            "pageType": "LAYOUT",
+            "pageElements": [
+                {
+                    "objectId": "p2_i0",
+                    "size": {
+                        "width": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        },
+                        "height": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        }
+                    },
+                    "transform": {
+                        "scaleX": 2.8402,
+                        "scaleY": 0.6842,
+                        "translateX": 311708.35000000003,
+                        "translateY": 744575,
+                        "unit": "EMU"
+                    },
+                    "shape": {
+                        "shapeType": "TEXT_BOX",
+                        "text": {
+                            "textElements": [
+                                {
+                                    "endIndex": 1,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "alignment": "CENTER",
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "endIndex": 1,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 52,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 1,
+                                    "endIndex": 2,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "alignment": "CENTER",
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 1,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 1,
+                                    "endIndex": 2,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 52,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 2,
+                                    "endIndex": 3,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "alignment": "CENTER",
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 2,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 2,
+                                    "endIndex": 3,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 52,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 3,
+                                    "endIndex": 4,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "alignment": "CENTER",
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 3,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 3,
+                                    "endIndex": 4,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 52,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 4,
+                                    "endIndex": 5,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "alignment": "CENTER",
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 4,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 4,
+                                    "endIndex": 5,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 52,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 5,
+                                    "endIndex": 6,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "alignment": "CENTER",
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 5,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 5,
+                                    "endIndex": 6,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 52,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 6,
+                                    "endIndex": 7,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "alignment": "CENTER",
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 6,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 6,
+                                    "endIndex": 7,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 52,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 7,
+                                    "endIndex": 8,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "alignment": "CENTER",
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 7,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 7,
+                                    "endIndex": 8,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 52,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 8,
+                                    "endIndex": 9,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "alignment": "CENTER",
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 8,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 8,
+                                    "endIndex": 9,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 52,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                }
+                            ],
+                            "lists": {
+                                "bodyPlaceholderListEntity": {
+                                    "listId": "bodyPlaceholderListEntity",
+                                    "nestingLevel": {
+                                        "0": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 52,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "1": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 52,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "2": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 52,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "3": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 52,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "4": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 52,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "5": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 52,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "6": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 52,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "7": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 52,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "8": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 52,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        },
+                        "shapeProperties": {
+                            "shapeBackgroundFill": {
+                                "propertyState": "INHERIT"
+                            },
+                            "outline": {
+                                "propertyState": "INHERIT"
+                            },
+                            "shadow": {
+                                "propertyState": "INHERIT"
+                            },
+                            "contentAlignment": "BOTTOM"
+                        },
+                        "placeholder": {
+                            "type": "CENTERED_TITLE",
+                            "parentObjectId": "p1_i0"
+                        }
+                    }
+                },
+                {
+                    "objectId": "p2_i1",
+                    "size": {
+                        "width": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        },
+                        "height": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        }
+                    },
+                    "transform": {
+                        "scaleX": 2.8402,
+                        "scaleY": 0.2642,
+                        "translateX": 311700,
+                        "translateY": 2834125,
+                        "unit": "EMU"
+                    },
+                    "shape": {
+                        "shapeType": "TEXT_BOX",
+                        "text": {
+                            "textElements": [
+                                {
+                                    "endIndex": 1,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "lineSpacing": 100,
+                                            "alignment": "CENTER",
+                                            "spaceBelow": {
+                                                "unit": "PT"
+                                            },
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "endIndex": 1,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 28,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 1,
+                                    "endIndex": 2,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "lineSpacing": 100,
+                                            "alignment": "CENTER",
+                                            "spaceBelow": {
+                                                "unit": "PT"
+                                            },
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 1,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 1,
+                                    "endIndex": 2,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 28,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 2,
+                                    "endIndex": 3,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "lineSpacing": 100,
+                                            "alignment": "CENTER",
+                                            "spaceBelow": {
+                                                "unit": "PT"
+                                            },
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 2,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 2,
+                                    "endIndex": 3,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 28,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 3,
+                                    "endIndex": 4,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "lineSpacing": 100,
+                                            "alignment": "CENTER",
+                                            "spaceBelow": {
+                                                "unit": "PT"
+                                            },
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 3,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 3,
+                                    "endIndex": 4,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 28,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 4,
+                                    "endIndex": 5,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "lineSpacing": 100,
+                                            "alignment": "CENTER",
+                                            "spaceBelow": {
+                                                "unit": "PT"
+                                            },
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 4,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 4,
+                                    "endIndex": 5,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 28,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 5,
+                                    "endIndex": 6,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "lineSpacing": 100,
+                                            "alignment": "CENTER",
+                                            "spaceBelow": {
+                                                "unit": "PT"
+                                            },
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 5,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 5,
+                                    "endIndex": 6,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 28,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 6,
+                                    "endIndex": 7,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "lineSpacing": 100,
+                                            "alignment": "CENTER",
+                                            "spaceBelow": {
+                                                "unit": "PT"
+                                            },
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 6,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 6,
+                                    "endIndex": 7,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 28,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 7,
+                                    "endIndex": 8,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "lineSpacing": 100,
+                                            "alignment": "CENTER",
+                                            "spaceBelow": {
+                                                "unit": "PT"
+                                            },
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 7,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 7,
+                                    "endIndex": 8,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 28,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 8,
+                                    "endIndex": 9,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "lineSpacing": 100,
+                                            "alignment": "CENTER",
+                                            "spaceBelow": {
+                                                "unit": "PT"
+                                            },
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 8,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 8,
+                                    "endIndex": 9,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 28,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                }
+                            ],
+                            "lists": {
+                                "bodyPlaceholderListEntity": {
+                                    "listId": "bodyPlaceholderListEntity",
+                                    "nestingLevel": {
+                                        "0": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 28,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "1": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 28,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "2": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 28,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "3": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 28,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "4": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 28,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "5": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 28,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "6": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 28,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "7": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 28,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "8": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 28,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        },
+                        "shapeProperties": {
+                            "shapeBackgroundFill": {
+                                "propertyState": "INHERIT"
+                            },
+                            "outline": {
+                                "propertyState": "INHERIT"
+                            },
+                            "shadow": {
+                                "propertyState": "INHERIT"
+                            }
+                        },
+                        "placeholder": {
+                            "type": "SUBTITLE",
+                            "parentObjectId": "p1_i1"
+                        }
+                    }
+                },
+                {
+                    "objectId": "p2_i2",
+                    "size": {
+                        "width": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        },
+                        "height": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        }
+                    },
+                    "transform": {
+                        "scaleX": 0.1829,
+                        "scaleY": 0.1312,
+                        "translateX": 8472457.8125,
+                        "translateY": 4663216.797499999,
+                        "unit": "EMU"
+                    },
+                    "shape": {
+                        "shapeType": "TEXT_BOX",
+                        "text": {
+                            "textElements": [
+                                {
+                                    "endIndex": 2,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        }
+                                    }
+                                },
+                                {
+                                    "endIndex": 1,
+                                    "autoText": {
+                                        "type": "SLIDE_NUMBER",
+                                        "content": "#",
+                                        "style": {}
+                                    }
+                                },
+                                {
+                                    "startIndex": 1,
+                                    "endIndex": 2,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {}
+                                    }
+                                }
+                            ]
+                        },
+                        "shapeProperties": {
+                            "shapeBackgroundFill": {
+                                "propertyState": "INHERIT"
+                            },
+                            "outline": {
+                                "propertyState": "INHERIT"
+                            },
+                            "shadow": {
+                                "propertyState": "INHERIT"
+                            }
+                        },
+                        "placeholder": {
+                            "type": "SLIDE_NUMBER",
+                            "parentObjectId": "p1_i2"
+                        }
+                    }
+                }
+            ],
+            "layoutProperties": {
+                "masterObjectId": "simple-light-2",
+                "name": "TITLE",
+                "displayName": "Title slide"
+            },
+            "pageProperties": {
+                "pageBackgroundFill": {
+                    "propertyState": "INHERIT"
+                }
+            }
+        },
+        {
+            "objectId": "p3",
+            "pageType": "LAYOUT",
+            "pageElements": [
+                {
+                    "objectId": "p3_i0",
+                    "size": {
+                        "width": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        },
+                        "height": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        }
+                    },
+                    "transform": {
+                        "scaleX": 2.8402,
+                        "scaleY": 0.2806,
+                        "translateX": 311700,
+                        "translateY": 2150850,
+                        "unit": "EMU"
+                    },
+                    "shape": {
+                        "shapeType": "TEXT_BOX",
+                        "text": {
+                            "textElements": [
+                                {
+                                    "endIndex": 1,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "alignment": "CENTER",
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "endIndex": 1,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 36,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 1,
+                                    "endIndex": 2,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "alignment": "CENTER",
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 1,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 1,
+                                    "endIndex": 2,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 36,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 2,
+                                    "endIndex": 3,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "alignment": "CENTER",
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 2,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 2,
+                                    "endIndex": 3,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 36,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 3,
+                                    "endIndex": 4,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "alignment": "CENTER",
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 3,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 3,
+                                    "endIndex": 4,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 36,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 4,
+                                    "endIndex": 5,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "alignment": "CENTER",
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 4,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 4,
+                                    "endIndex": 5,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 36,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 5,
+                                    "endIndex": 6,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "alignment": "CENTER",
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 5,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 5,
+                                    "endIndex": 6,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 36,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 6,
+                                    "endIndex": 7,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "alignment": "CENTER",
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 6,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 6,
+                                    "endIndex": 7,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 36,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 7,
+                                    "endIndex": 8,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "alignment": "CENTER",
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 7,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 7,
+                                    "endIndex": 8,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 36,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 8,
+                                    "endIndex": 9,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "alignment": "CENTER",
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 8,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 8,
+                                    "endIndex": 9,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 36,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                }
+                            ],
+                            "lists": {
+                                "bodyPlaceholderListEntity": {
+                                    "listId": "bodyPlaceholderListEntity",
+                                    "nestingLevel": {
+                                        "0": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 36,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "1": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 36,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "2": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 36,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "3": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 36,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "4": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 36,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "5": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 36,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "6": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 36,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "7": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 36,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "8": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 36,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        },
+                        "shapeProperties": {
+                            "shapeBackgroundFill": {
+                                "propertyState": "INHERIT"
+                            },
+                            "outline": {
+                                "propertyState": "INHERIT"
+                            },
+                            "shadow": {
+                                "propertyState": "INHERIT"
+                            },
+                            "contentAlignment": "MIDDLE"
+                        },
+                        "placeholder": {
+                            "type": "TITLE",
+                            "parentObjectId": "p1_i0"
+                        }
+                    }
+                },
+                {
+                    "objectId": "p3_i1",
+                    "size": {
+                        "width": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        },
+                        "height": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        }
+                    },
+                    "transform": {
+                        "scaleX": 0.1829,
+                        "scaleY": 0.1312,
+                        "translateX": 8472457.8125,
+                        "translateY": 4663216.797499999,
+                        "unit": "EMU"
+                    },
+                    "shape": {
+                        "shapeType": "TEXT_BOX",
+                        "text": {
+                            "textElements": [
+                                {
+                                    "endIndex": 2,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        }
+                                    }
+                                },
+                                {
+                                    "endIndex": 1,
+                                    "autoText": {
+                                        "type": "SLIDE_NUMBER",
+                                        "content": "#",
+                                        "style": {}
+                                    }
+                                },
+                                {
+                                    "startIndex": 1,
+                                    "endIndex": 2,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {}
+                                    }
+                                }
+                            ]
+                        },
+                        "shapeProperties": {
+                            "shapeBackgroundFill": {
+                                "propertyState": "INHERIT"
+                            },
+                            "outline": {
+                                "propertyState": "INHERIT"
+                            },
+                            "shadow": {
+                                "propertyState": "INHERIT"
+                            }
+                        },
+                        "placeholder": {
+                            "type": "SLIDE_NUMBER",
+                            "parentObjectId": "p1_i2"
+                        }
+                    }
+                }
+            ],
+            "layoutProperties": {
+                "masterObjectId": "simple-light-2",
+                "name": "SECTION_HEADER",
+                "displayName": "Section header"
+            },
+            "pageProperties": {
+                "pageBackgroundFill": {
+                    "propertyState": "INHERIT"
+                }
+            }
+        },
+        {
+            "objectId": "p4",
+            "pageType": "LAYOUT",
+            "pageElements": [
+                {
+                    "objectId": "p4_i0",
+                    "size": {
+                        "width": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        },
+                        "height": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        }
+                    },
+                    "transform": {
+                        "scaleX": 2.8402,
+                        "scaleY": 0.1909,
+                        "translateX": 311700,
+                        "translateY": 445025,
+                        "unit": "EMU"
+                    },
+                    "shape": {
+                        "shapeType": "TEXT_BOX",
+                        "text": {
+                            "textElements": [
+                                {
+                                    "endIndex": 1,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "endIndex": 1,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {}
+                                    }
+                                },
+                                {
+                                    "startIndex": 1,
+                                    "endIndex": 2,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 1,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 1,
+                                    "endIndex": 2,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {}
+                                    }
+                                },
+                                {
+                                    "startIndex": 2,
+                                    "endIndex": 3,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 2,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 2,
+                                    "endIndex": 3,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {}
+                                    }
+                                },
+                                {
+                                    "startIndex": 3,
+                                    "endIndex": 4,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 3,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 3,
+                                    "endIndex": 4,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {}
+                                    }
+                                },
+                                {
+                                    "startIndex": 4,
+                                    "endIndex": 5,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 4,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 4,
+                                    "endIndex": 5,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {}
+                                    }
+                                },
+                                {
+                                    "startIndex": 5,
+                                    "endIndex": 6,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 5,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 5,
+                                    "endIndex": 6,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {}
+                                    }
+                                },
+                                {
+                                    "startIndex": 6,
+                                    "endIndex": 7,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 6,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 6,
+                                    "endIndex": 7,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {}
+                                    }
+                                },
+                                {
+                                    "startIndex": 7,
+                                    "endIndex": 8,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 7,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 7,
+                                    "endIndex": 8,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {}
+                                    }
+                                },
+                                {
+                                    "startIndex": 8,
+                                    "endIndex": 9,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 8,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 8,
+                                    "endIndex": 9,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {}
+                                    }
+                                }
+                            ],
+                            "lists": {
+                                "bodyPlaceholderListEntity": {
+                                    "listId": "bodyPlaceholderListEntity",
+                                    "nestingLevel": {
+                                        "0": {
+                                            "bulletStyle": {}
+                                        },
+                                        "1": {
+                                            "bulletStyle": {}
+                                        },
+                                        "2": {
+                                            "bulletStyle": {}
+                                        },
+                                        "3": {
+                                            "bulletStyle": {}
+                                        },
+                                        "4": {
+                                            "bulletStyle": {}
+                                        },
+                                        "5": {
+                                            "bulletStyle": {}
+                                        },
+                                        "6": {
+                                            "bulletStyle": {}
+                                        },
+                                        "7": {
+                                            "bulletStyle": {}
+                                        },
+                                        "8": {
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                }
+                            }
+                        },
+                        "shapeProperties": {
+                            "shapeBackgroundFill": {
+                                "propertyState": "INHERIT"
+                            },
+                            "outline": {
+                                "propertyState": "INHERIT"
+                            },
+                            "shadow": {
+                                "propertyState": "INHERIT"
+                            }
+                        },
+                        "placeholder": {
+                            "type": "TITLE",
+                            "parentObjectId": "p1_i0"
+                        }
+                    }
+                },
+                {
+                    "objectId": "p4_i1",
+                    "size": {
+                        "width": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        },
+                        "height": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        }
+                    },
+                    "transform": {
+                        "scaleX": 2.8402,
+                        "scaleY": 1.1388,
+                        "translateX": 311700,
+                        "translateY": 1152475,
+                        "unit": "EMU"
+                    },
+                    "shape": {
+                        "shapeType": "TEXT_BOX",
+                        "text": {
+                            "textElements": [
+                                {
+                                    "endIndex": 1,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "glyph": "●",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "endIndex": 1,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {}
+                                    }
+                                },
+                                {
+                                    "startIndex": 1,
+                                    "endIndex": 2,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 1,
+                                            "glyph": "○",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 1,
+                                    "endIndex": 2,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {}
+                                    }
+                                },
+                                {
+                                    "startIndex": 2,
+                                    "endIndex": 3,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 2,
+                                            "glyph": "■",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 2,
+                                    "endIndex": 3,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {}
+                                    }
+                                },
+                                {
+                                    "startIndex": 3,
+                                    "endIndex": 4,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 3,
+                                            "glyph": "●",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 3,
+                                    "endIndex": 4,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {}
+                                    }
+                                },
+                                {
+                                    "startIndex": 4,
+                                    "endIndex": 5,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 4,
+                                            "glyph": "○",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 4,
+                                    "endIndex": 5,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {}
+                                    }
+                                },
+                                {
+                                    "startIndex": 5,
+                                    "endIndex": 6,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 5,
+                                            "glyph": "■",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 5,
+                                    "endIndex": 6,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {}
+                                    }
+                                },
+                                {
+                                    "startIndex": 6,
+                                    "endIndex": 7,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 6,
+                                            "glyph": "●",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 6,
+                                    "endIndex": 7,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {}
+                                    }
+                                },
+                                {
+                                    "startIndex": 7,
+                                    "endIndex": 8,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 7,
+                                            "glyph": "○",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 7,
+                                    "endIndex": 8,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {}
+                                    }
+                                },
+                                {
+                                    "startIndex": 8,
+                                    "endIndex": 9,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 8,
+                                            "glyph": "■",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 8,
+                                    "endIndex": 9,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {}
+                                    }
+                                }
+                            ],
+                            "lists": {
+                                "bodyPlaceholderListEntity": {
+                                    "listId": "bodyPlaceholderListEntity",
+                                    "nestingLevel": {
+                                        "0": {
+                                            "bulletStyle": {}
+                                        },
+                                        "1": {
+                                            "bulletStyle": {}
+                                        },
+                                        "2": {
+                                            "bulletStyle": {}
+                                        },
+                                        "3": {
+                                            "bulletStyle": {}
+                                        },
+                                        "4": {
+                                            "bulletStyle": {}
+                                        },
+                                        "5": {
+                                            "bulletStyle": {}
+                                        },
+                                        "6": {
+                                            "bulletStyle": {}
+                                        },
+                                        "7": {
+                                            "bulletStyle": {}
+                                        },
+                                        "8": {
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                }
+                            }
+                        },
+                        "shapeProperties": {
+                            "shapeBackgroundFill": {
+                                "propertyState": "INHERIT"
+                            },
+                            "outline": {
+                                "propertyState": "INHERIT"
+                            },
+                            "shadow": {
+                                "propertyState": "INHERIT"
+                            }
+                        },
+                        "placeholder": {
+                            "type": "BODY",
+                            "parentObjectId": "p1_i1"
+                        }
+                    }
+                },
+                {
+                    "objectId": "p4_i2",
+                    "size": {
+                        "width": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        },
+                        "height": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        }
+                    },
+                    "transform": {
+                        "scaleX": 0.1829,
+                        "scaleY": 0.1312,
+                        "translateX": 8472457.8125,
+                        "translateY": 4663216.797499999,
+                        "unit": "EMU"
+                    },
+                    "shape": {
+                        "shapeType": "TEXT_BOX",
+                        "text": {
+                            "textElements": [
+                                {
+                                    "endIndex": 2,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        }
+                                    }
+                                },
+                                {
+                                    "endIndex": 1,
+                                    "autoText": {
+                                        "type": "SLIDE_NUMBER",
+                                        "content": "#",
+                                        "style": {}
+                                    }
+                                },
+                                {
+                                    "startIndex": 1,
+                                    "endIndex": 2,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {}
+                                    }
+                                }
+                            ]
+                        },
+                        "shapeProperties": {
+                            "shapeBackgroundFill": {
+                                "propertyState": "INHERIT"
+                            },
+                            "outline": {
+                                "propertyState": "INHERIT"
+                            },
+                            "shadow": {
+                                "propertyState": "INHERIT"
+                            }
+                        },
+                        "placeholder": {
+                            "type": "SLIDE_NUMBER",
+                            "parentObjectId": "p1_i2"
+                        }
+                    }
+                }
+            ],
+            "layoutProperties": {
+                "masterObjectId": "simple-light-2",
+                "name": "TITLE_AND_BODY",
+                "displayName": "Title and body"
+            },
+            "pageProperties": {
+                "pageBackgroundFill": {
+                    "propertyState": "INHERIT"
+                }
+            }
+        },
+        {
+            "objectId": "p5",
+            "pageType": "LAYOUT",
+            "pageElements": [
+                {
+                    "objectId": "p5_i0",
+                    "size": {
+                        "width": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        },
+                        "height": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        }
+                    },
+                    "transform": {
+                        "scaleX": 2.8402,
+                        "scaleY": 0.1909,
+                        "translateX": 311700,
+                        "translateY": 445025,
+                        "unit": "EMU"
+                    },
+                    "shape": {
+                        "shapeType": "TEXT_BOX",
+                        "text": {
+                            "textElements": [
+                                {
+                                    "endIndex": 1,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "endIndex": 1,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {}
+                                    }
+                                },
+                                {
+                                    "startIndex": 1,
+                                    "endIndex": 2,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 1,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 1,
+                                    "endIndex": 2,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {}
+                                    }
+                                },
+                                {
+                                    "startIndex": 2,
+                                    "endIndex": 3,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 2,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 2,
+                                    "endIndex": 3,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {}
+                                    }
+                                },
+                                {
+                                    "startIndex": 3,
+                                    "endIndex": 4,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 3,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 3,
+                                    "endIndex": 4,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {}
+                                    }
+                                },
+                                {
+                                    "startIndex": 4,
+                                    "endIndex": 5,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 4,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 4,
+                                    "endIndex": 5,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {}
+                                    }
+                                },
+                                {
+                                    "startIndex": 5,
+                                    "endIndex": 6,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 5,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 5,
+                                    "endIndex": 6,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {}
+                                    }
+                                },
+                                {
+                                    "startIndex": 6,
+                                    "endIndex": 7,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 6,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 6,
+                                    "endIndex": 7,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {}
+                                    }
+                                },
+                                {
+                                    "startIndex": 7,
+                                    "endIndex": 8,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 7,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 7,
+                                    "endIndex": 8,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {}
+                                    }
+                                },
+                                {
+                                    "startIndex": 8,
+                                    "endIndex": 9,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 8,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 8,
+                                    "endIndex": 9,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {}
+                                    }
+                                }
+                            ],
+                            "lists": {
+                                "bodyPlaceholderListEntity": {
+                                    "listId": "bodyPlaceholderListEntity",
+                                    "nestingLevel": {
+                                        "0": {
+                                            "bulletStyle": {}
+                                        },
+                                        "1": {
+                                            "bulletStyle": {}
+                                        },
+                                        "2": {
+                                            "bulletStyle": {}
+                                        },
+                                        "3": {
+                                            "bulletStyle": {}
+                                        },
+                                        "4": {
+                                            "bulletStyle": {}
+                                        },
+                                        "5": {
+                                            "bulletStyle": {}
+                                        },
+                                        "6": {
+                                            "bulletStyle": {}
+                                        },
+                                        "7": {
+                                            "bulletStyle": {}
+                                        },
+                                        "8": {
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                }
+                            }
+                        },
+                        "shapeProperties": {
+                            "shapeBackgroundFill": {
+                                "propertyState": "INHERIT"
+                            },
+                            "outline": {
+                                "propertyState": "INHERIT"
+                            },
+                            "shadow": {
+                                "propertyState": "INHERIT"
+                            }
+                        },
+                        "placeholder": {
+                            "type": "TITLE",
+                            "parentObjectId": "p1_i0"
+                        }
+                    }
+                },
+                {
+                    "objectId": "p5_i1",
+                    "size": {
+                        "width": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        },
+                        "height": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        }
+                    },
+                    "transform": {
+                        "scaleX": 1.3333,
+                        "scaleY": 1.1388,
+                        "translateX": 311700,
+                        "translateY": 1152475,
+                        "unit": "EMU"
+                    },
+                    "shape": {
+                        "shapeType": "TEXT_BOX",
+                        "text": {
+                            "textElements": [
+                                {
+                                    "endIndex": 1,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "glyph": "●",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "endIndex": 1,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 14,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 1,
+                                    "endIndex": 2,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 1,
+                                            "glyph": "○",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 1,
+                                    "endIndex": 2,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 12,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 2,
+                                    "endIndex": 3,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 2,
+                                            "glyph": "■",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 2,
+                                    "endIndex": 3,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 12,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 3,
+                                    "endIndex": 4,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 3,
+                                            "glyph": "●",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 3,
+                                    "endIndex": 4,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 12,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 4,
+                                    "endIndex": 5,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 4,
+                                            "glyph": "○",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 4,
+                                    "endIndex": 5,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 12,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 5,
+                                    "endIndex": 6,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 5,
+                                            "glyph": "■",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 5,
+                                    "endIndex": 6,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 12,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 6,
+                                    "endIndex": 7,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 6,
+                                            "glyph": "●",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 6,
+                                    "endIndex": 7,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 12,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 7,
+                                    "endIndex": 8,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 7,
+                                            "glyph": "○",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 7,
+                                    "endIndex": 8,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 12,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 8,
+                                    "endIndex": 9,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 8,
+                                            "glyph": "■",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 8,
+                                    "endIndex": 9,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 12,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                }
+                            ],
+                            "lists": {
+                                "bodyPlaceholderListEntity": {
+                                    "listId": "bodyPlaceholderListEntity",
+                                    "nestingLevel": {
+                                        "0": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 14,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "1": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 12,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "2": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 12,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "3": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 12,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "4": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 12,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "5": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 12,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "6": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 12,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "7": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 12,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "8": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 12,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        },
+                        "shapeProperties": {
+                            "shapeBackgroundFill": {
+                                "propertyState": "INHERIT"
+                            },
+                            "outline": {
+                                "propertyState": "INHERIT"
+                            },
+                            "shadow": {
+                                "propertyState": "INHERIT"
+                            }
+                        },
+                        "placeholder": {
+                            "type": "BODY",
+                            "parentObjectId": "p1_i1"
+                        }
+                    }
+                },
+                {
+                    "objectId": "p5_i2",
+                    "size": {
+                        "width": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        },
+                        "height": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        }
+                    },
+                    "transform": {
+                        "scaleX": 1.3333,
+                        "scaleY": 1.1388,
+                        "translateX": 4832400,
+                        "translateY": 1152475,
+                        "unit": "EMU"
+                    },
+                    "shape": {
+                        "shapeType": "TEXT_BOX",
+                        "text": {
+                            "textElements": [
+                                {
+                                    "endIndex": 1,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "glyph": "●",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "endIndex": 1,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 14,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 1,
+                                    "endIndex": 2,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 1,
+                                            "glyph": "○",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 1,
+                                    "endIndex": 2,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 12,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 2,
+                                    "endIndex": 3,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 2,
+                                            "glyph": "■",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 2,
+                                    "endIndex": 3,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 12,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 3,
+                                    "endIndex": 4,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 3,
+                                            "glyph": "●",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 3,
+                                    "endIndex": 4,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 12,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 4,
+                                    "endIndex": 5,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 4,
+                                            "glyph": "○",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 4,
+                                    "endIndex": 5,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 12,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 5,
+                                    "endIndex": 6,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 5,
+                                            "glyph": "■",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 5,
+                                    "endIndex": 6,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 12,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 6,
+                                    "endIndex": 7,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 6,
+                                            "glyph": "●",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 6,
+                                    "endIndex": 7,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 12,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 7,
+                                    "endIndex": 8,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 7,
+                                            "glyph": "○",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 7,
+                                    "endIndex": 8,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 12,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 8,
+                                    "endIndex": 9,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 8,
+                                            "glyph": "■",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 8,
+                                    "endIndex": 9,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 12,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                }
+                            ],
+                            "lists": {
+                                "bodyPlaceholderListEntity": {
+                                    "listId": "bodyPlaceholderListEntity",
+                                    "nestingLevel": {
+                                        "0": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 14,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "1": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 12,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "2": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 12,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "3": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 12,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "4": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 12,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "5": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 12,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "6": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 12,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "7": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 12,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "8": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 12,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        },
+                        "shapeProperties": {
+                            "shapeBackgroundFill": {
+                                "propertyState": "INHERIT"
+                            },
+                            "outline": {
+                                "propertyState": "INHERIT"
+                            },
+                            "shadow": {
+                                "propertyState": "INHERIT"
+                            }
+                        },
+                        "placeholder": {
+                            "type": "BODY",
+                            "index": 1,
+                            "parentObjectId": "p1_i1"
+                        }
+                    }
+                },
+                {
+                    "objectId": "p5_i3",
+                    "size": {
+                        "width": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        },
+                        "height": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        }
+                    },
+                    "transform": {
+                        "scaleX": 0.1829,
+                        "scaleY": 0.1312,
+                        "translateX": 8472457.8125,
+                        "translateY": 4663216.797499999,
+                        "unit": "EMU"
+                    },
+                    "shape": {
+                        "shapeType": "TEXT_BOX",
+                        "text": {
+                            "textElements": [
+                                {
+                                    "endIndex": 2,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        }
+                                    }
+                                },
+                                {
+                                    "endIndex": 1,
+                                    "autoText": {
+                                        "type": "SLIDE_NUMBER",
+                                        "content": "#",
+                                        "style": {}
+                                    }
+                                },
+                                {
+                                    "startIndex": 1,
+                                    "endIndex": 2,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {}
+                                    }
+                                }
+                            ]
+                        },
+                        "shapeProperties": {
+                            "shapeBackgroundFill": {
+                                "propertyState": "INHERIT"
+                            },
+                            "outline": {
+                                "propertyState": "INHERIT"
+                            },
+                            "shadow": {
+                                "propertyState": "INHERIT"
+                            }
+                        },
+                        "placeholder": {
+                            "type": "SLIDE_NUMBER",
+                            "parentObjectId": "p1_i2"
+                        }
+                    }
+                }
+            ],
+            "layoutProperties": {
+                "masterObjectId": "simple-light-2",
+                "name": "TITLE_AND_TWO_COLUMNS",
+                "displayName": "Title and two columns"
+            },
+            "pageProperties": {
+                "pageBackgroundFill": {
+                    "propertyState": "INHERIT"
+                }
+            }
+        },
+        {
+            "objectId": "p6",
+            "pageType": "LAYOUT",
+            "pageElements": [
+                {
+                    "objectId": "p6_i0",
+                    "size": {
+                        "width": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        },
+                        "height": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        }
+                    },
+                    "transform": {
+                        "scaleX": 2.8402,
+                        "scaleY": 0.1909,
+                        "translateX": 311700,
+                        "translateY": 445025,
+                        "unit": "EMU"
+                    },
+                    "shape": {
+                        "shapeType": "TEXT_BOX",
+                        "text": {
+                            "textElements": [
+                                {
+                                    "endIndex": 1,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "endIndex": 1,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {}
+                                    }
+                                },
+                                {
+                                    "startIndex": 1,
+                                    "endIndex": 2,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 1,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 1,
+                                    "endIndex": 2,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {}
+                                    }
+                                },
+                                {
+                                    "startIndex": 2,
+                                    "endIndex": 3,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 2,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 2,
+                                    "endIndex": 3,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {}
+                                    }
+                                },
+                                {
+                                    "startIndex": 3,
+                                    "endIndex": 4,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 3,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 3,
+                                    "endIndex": 4,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {}
+                                    }
+                                },
+                                {
+                                    "startIndex": 4,
+                                    "endIndex": 5,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 4,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 4,
+                                    "endIndex": 5,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {}
+                                    }
+                                },
+                                {
+                                    "startIndex": 5,
+                                    "endIndex": 6,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 5,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 5,
+                                    "endIndex": 6,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {}
+                                    }
+                                },
+                                {
+                                    "startIndex": 6,
+                                    "endIndex": 7,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 6,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 6,
+                                    "endIndex": 7,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {}
+                                    }
+                                },
+                                {
+                                    "startIndex": 7,
+                                    "endIndex": 8,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 7,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 7,
+                                    "endIndex": 8,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {}
+                                    }
+                                },
+                                {
+                                    "startIndex": 8,
+                                    "endIndex": 9,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 8,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 8,
+                                    "endIndex": 9,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {}
+                                    }
+                                }
+                            ],
+                            "lists": {
+                                "bodyPlaceholderListEntity": {
+                                    "listId": "bodyPlaceholderListEntity",
+                                    "nestingLevel": {
+                                        "0": {
+                                            "bulletStyle": {}
+                                        },
+                                        "1": {
+                                            "bulletStyle": {}
+                                        },
+                                        "2": {
+                                            "bulletStyle": {}
+                                        },
+                                        "3": {
+                                            "bulletStyle": {}
+                                        },
+                                        "4": {
+                                            "bulletStyle": {}
+                                        },
+                                        "5": {
+                                            "bulletStyle": {}
+                                        },
+                                        "6": {
+                                            "bulletStyle": {}
+                                        },
+                                        "7": {
+                                            "bulletStyle": {}
+                                        },
+                                        "8": {
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                }
+                            }
+                        },
+                        "shapeProperties": {
+                            "shapeBackgroundFill": {
+                                "propertyState": "INHERIT"
+                            },
+                            "outline": {
+                                "propertyState": "INHERIT"
+                            },
+                            "shadow": {
+                                "propertyState": "INHERIT"
+                            }
+                        },
+                        "placeholder": {
+                            "type": "TITLE",
+                            "parentObjectId": "p1_i0"
+                        }
+                    }
+                },
+                {
+                    "objectId": "p6_i1",
+                    "size": {
+                        "width": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        },
+                        "height": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        }
+                    },
+                    "transform": {
+                        "scaleX": 0.1829,
+                        "scaleY": 0.1312,
+                        "translateX": 8472457.8125,
+                        "translateY": 4663216.797499999,
+                        "unit": "EMU"
+                    },
+                    "shape": {
+                        "shapeType": "TEXT_BOX",
+                        "text": {
+                            "textElements": [
+                                {
+                                    "endIndex": 2,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        }
+                                    }
+                                },
+                                {
+                                    "endIndex": 1,
+                                    "autoText": {
+                                        "type": "SLIDE_NUMBER",
+                                        "content": "#",
+                                        "style": {}
+                                    }
+                                },
+                                {
+                                    "startIndex": 1,
+                                    "endIndex": 2,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {}
+                                    }
+                                }
+                            ]
+                        },
+                        "shapeProperties": {
+                            "shapeBackgroundFill": {
+                                "propertyState": "INHERIT"
+                            },
+                            "outline": {
+                                "propertyState": "INHERIT"
+                            },
+                            "shadow": {
+                                "propertyState": "INHERIT"
+                            }
+                        },
+                        "placeholder": {
+                            "type": "SLIDE_NUMBER",
+                            "parentObjectId": "p1_i2"
+                        }
+                    }
+                }
+            ],
+            "layoutProperties": {
+                "masterObjectId": "simple-light-2",
+                "name": "TITLE_ONLY",
+                "displayName": "Title only"
+            },
+            "pageProperties": {
+                "pageBackgroundFill": {
+                    "propertyState": "INHERIT"
+                }
+            }
+        },
+        {
+            "objectId": "p7",
+            "pageType": "LAYOUT",
+            "pageElements": [
+                {
+                    "objectId": "p7_i0",
+                    "size": {
+                        "width": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        },
+                        "height": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        }
+                    },
+                    "transform": {
+                        "scaleX": 0.936,
+                        "scaleY": 0.2519,
+                        "translateX": 311700,
+                        "translateY": 555600,
+                        "unit": "EMU"
+                    },
+                    "shape": {
+                        "shapeType": "TEXT_BOX",
+                        "text": {
+                            "textElements": [
+                                {
+                                    "endIndex": 1,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "endIndex": 1,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 24,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 1,
+                                    "endIndex": 2,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 1,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 1,
+                                    "endIndex": 2,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 24,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 2,
+                                    "endIndex": 3,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 2,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 2,
+                                    "endIndex": 3,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 24,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 3,
+                                    "endIndex": 4,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 3,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 3,
+                                    "endIndex": 4,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 24,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 4,
+                                    "endIndex": 5,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 4,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 4,
+                                    "endIndex": 5,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 24,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 5,
+                                    "endIndex": 6,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 5,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 5,
+                                    "endIndex": 6,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 24,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 6,
+                                    "endIndex": 7,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 6,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 6,
+                                    "endIndex": 7,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 24,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 7,
+                                    "endIndex": 8,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 7,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 7,
+                                    "endIndex": 8,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 24,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 8,
+                                    "endIndex": 9,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 8,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 8,
+                                    "endIndex": 9,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 24,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                }
+                            ],
+                            "lists": {
+                                "bodyPlaceholderListEntity": {
+                                    "listId": "bodyPlaceholderListEntity",
+                                    "nestingLevel": {
+                                        "0": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 24,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "1": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 24,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "2": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 24,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "3": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 24,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "4": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 24,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "5": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 24,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "6": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 24,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "7": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 24,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "8": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 24,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        },
+                        "shapeProperties": {
+                            "shapeBackgroundFill": {
+                                "propertyState": "INHERIT"
+                            },
+                            "outline": {
+                                "propertyState": "INHERIT"
+                            },
+                            "shadow": {
+                                "propertyState": "INHERIT"
+                            },
+                            "contentAlignment": "BOTTOM"
+                        },
+                        "placeholder": {
+                            "type": "TITLE",
+                            "parentObjectId": "p1_i0"
+                        }
+                    }
+                },
+                {
+                    "objectId": "p7_i1",
+                    "size": {
+                        "width": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        },
+                        "height": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        }
+                    },
+                    "transform": {
+                        "scaleX": 0.936,
+                        "scaleY": 1.0598,
+                        "translateX": 311700,
+                        "translateY": 1389600,
+                        "unit": "EMU"
+                    },
+                    "shape": {
+                        "shapeType": "TEXT_BOX",
+                        "text": {
+                            "textElements": [
+                                {
+                                    "endIndex": 1,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "glyph": "●",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "endIndex": 1,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 12,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 1,
+                                    "endIndex": 2,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 1,
+                                            "glyph": "○",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 1,
+                                    "endIndex": 2,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 12,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 2,
+                                    "endIndex": 3,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 2,
+                                            "glyph": "■",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 2,
+                                    "endIndex": 3,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 12,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 3,
+                                    "endIndex": 4,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 3,
+                                            "glyph": "●",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 3,
+                                    "endIndex": 4,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 12,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 4,
+                                    "endIndex": 5,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 4,
+                                            "glyph": "○",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 4,
+                                    "endIndex": 5,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 12,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 5,
+                                    "endIndex": 6,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 5,
+                                            "glyph": "■",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 5,
+                                    "endIndex": 6,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 12,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 6,
+                                    "endIndex": 7,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 6,
+                                            "glyph": "●",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 6,
+                                    "endIndex": 7,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 12,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 7,
+                                    "endIndex": 8,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 7,
+                                            "glyph": "○",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 7,
+                                    "endIndex": 8,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 12,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 8,
+                                    "endIndex": 9,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 8,
+                                            "glyph": "■",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 8,
+                                    "endIndex": 9,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 12,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                }
+                            ],
+                            "lists": {
+                                "bodyPlaceholderListEntity": {
+                                    "listId": "bodyPlaceholderListEntity",
+                                    "nestingLevel": {
+                                        "0": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 12,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "1": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 12,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "2": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 12,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "3": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 12,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "4": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 12,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "5": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 12,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "6": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 12,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "7": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 12,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "8": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 12,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        },
+                        "shapeProperties": {
+                            "shapeBackgroundFill": {
+                                "propertyState": "INHERIT"
+                            },
+                            "outline": {
+                                "propertyState": "INHERIT"
+                            },
+                            "shadow": {
+                                "propertyState": "INHERIT"
+                            }
+                        },
+                        "placeholder": {
+                            "type": "BODY",
+                            "parentObjectId": "p1_i1"
+                        }
+                    }
+                },
+                {
+                    "objectId": "p7_i2",
+                    "size": {
+                        "width": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        },
+                        "height": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        }
+                    },
+                    "transform": {
+                        "scaleX": 0.1829,
+                        "scaleY": 0.1312,
+                        "translateX": 8472457.8125,
+                        "translateY": 4663216.797499999,
+                        "unit": "EMU"
+                    },
+                    "shape": {
+                        "shapeType": "TEXT_BOX",
+                        "text": {
+                            "textElements": [
+                                {
+                                    "endIndex": 2,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        }
+                                    }
+                                },
+                                {
+                                    "endIndex": 1,
+                                    "autoText": {
+                                        "type": "SLIDE_NUMBER",
+                                        "content": "#",
+                                        "style": {}
+                                    }
+                                },
+                                {
+                                    "startIndex": 1,
+                                    "endIndex": 2,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {}
+                                    }
+                                }
+                            ]
+                        },
+                        "shapeProperties": {
+                            "shapeBackgroundFill": {
+                                "propertyState": "INHERIT"
+                            },
+                            "outline": {
+                                "propertyState": "INHERIT"
+                            },
+                            "shadow": {
+                                "propertyState": "INHERIT"
+                            }
+                        },
+                        "placeholder": {
+                            "type": "SLIDE_NUMBER",
+                            "parentObjectId": "p1_i2"
+                        }
+                    }
+                }
+            ],
+            "layoutProperties": {
+                "masterObjectId": "simple-light-2",
+                "name": "ONE_COLUMN_TEXT",
+                "displayName": "One column text"
+            },
+            "pageProperties": {
+                "pageBackgroundFill": {
+                    "propertyState": "INHERIT"
+                }
+            }
+        },
+        {
+            "objectId": "p8",
+            "pageType": "LAYOUT",
+            "pageElements": [
+                {
+                    "objectId": "p8_i0",
+                    "size": {
+                        "width": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        },
+                        "height": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        }
+                    },
+                    "transform": {
+                        "scaleX": 2.1226,
+                        "scaleY": 1.3636,
+                        "translateX": 490250,
+                        "translateY": 450150,
+                        "unit": "EMU"
+                    },
+                    "shape": {
+                        "shapeType": "TEXT_BOX",
+                        "text": {
+                            "textElements": [
+                                {
+                                    "endIndex": 1,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "endIndex": 1,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 48,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 1,
+                                    "endIndex": 2,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 1,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 1,
+                                    "endIndex": 2,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 48,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 2,
+                                    "endIndex": 3,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 2,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 2,
+                                    "endIndex": 3,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 48,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 3,
+                                    "endIndex": 4,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 3,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 3,
+                                    "endIndex": 4,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 48,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 4,
+                                    "endIndex": 5,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 4,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 4,
+                                    "endIndex": 5,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 48,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 5,
+                                    "endIndex": 6,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 5,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 5,
+                                    "endIndex": 6,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 48,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 6,
+                                    "endIndex": 7,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 6,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 6,
+                                    "endIndex": 7,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 48,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 7,
+                                    "endIndex": 8,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 7,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 7,
+                                    "endIndex": 8,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 48,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 8,
+                                    "endIndex": 9,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 8,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 8,
+                                    "endIndex": 9,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 48,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                }
+                            ],
+                            "lists": {
+                                "bodyPlaceholderListEntity": {
+                                    "listId": "bodyPlaceholderListEntity",
+                                    "nestingLevel": {
+                                        "0": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 48,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "1": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 48,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "2": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 48,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "3": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 48,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "4": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 48,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "5": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 48,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "6": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 48,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "7": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 48,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "8": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 48,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        },
+                        "shapeProperties": {
+                            "shapeBackgroundFill": {
+                                "propertyState": "INHERIT"
+                            },
+                            "outline": {
+                                "propertyState": "INHERIT"
+                            },
+                            "shadow": {
+                                "propertyState": "INHERIT"
+                            },
+                            "contentAlignment": "MIDDLE"
+                        },
+                        "placeholder": {
+                            "type": "TITLE",
+                            "parentObjectId": "p1_i0"
+                        }
+                    }
+                },
+                {
+                    "objectId": "p8_i1",
+                    "size": {
+                        "width": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        },
+                        "height": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        }
+                    },
+                    "transform": {
+                        "scaleX": 0.1829,
+                        "scaleY": 0.1312,
+                        "translateX": 8472457.8125,
+                        "translateY": 4663216.797499999,
+                        "unit": "EMU"
+                    },
+                    "shape": {
+                        "shapeType": "TEXT_BOX",
+                        "text": {
+                            "textElements": [
+                                {
+                                    "endIndex": 2,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        }
+                                    }
+                                },
+                                {
+                                    "endIndex": 1,
+                                    "autoText": {
+                                        "type": "SLIDE_NUMBER",
+                                        "content": "#",
+                                        "style": {}
+                                    }
+                                },
+                                {
+                                    "startIndex": 1,
+                                    "endIndex": 2,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {}
+                                    }
+                                }
+                            ]
+                        },
+                        "shapeProperties": {
+                            "shapeBackgroundFill": {
+                                "propertyState": "INHERIT"
+                            },
+                            "outline": {
+                                "propertyState": "INHERIT"
+                            },
+                            "shadow": {
+                                "propertyState": "INHERIT"
+                            }
+                        },
+                        "placeholder": {
+                            "type": "SLIDE_NUMBER",
+                            "parentObjectId": "p1_i2"
+                        }
+                    }
+                }
+            ],
+            "layoutProperties": {
+                "masterObjectId": "simple-light-2",
+                "name": "MAIN_POINT",
+                "displayName": "Main point"
+            },
+            "pageProperties": {
+                "pageBackgroundFill": {
+                    "propertyState": "INHERIT"
+                }
+            }
+        },
+        {
+            "objectId": "p9",
+            "pageType": "LAYOUT",
+            "pageElements": [
+                {
+                    "objectId": "p9_i0",
+                    "size": {
+                        "width": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        },
+                        "height": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        }
+                    },
+                    "transform": {
+                        "scaleX": 1.524,
+                        "scaleY": 1.7145,
+                        "translateX": 4572000,
+                        "translateY": -125,
+                        "unit": "EMU"
+                    },
+                    "shape": {
+                        "shapeType": "RECTANGLE",
+                        "shapeProperties": {
+                            "shapeBackgroundFill": {
+                                "solidFill": {
+                                    "color": {
+                                        "themeColor": "LIGHT2"
+                                    },
+                                    "alpha": 1
+                                }
+                            },
+                            "outline": {
+                                "outlineFill": {
+                                    "solidFill": {
+                                        "color": {
+                                            "rgbColor": {}
+                                        },
+                                        "alpha": 1
+                                    }
+                                },
+                                "weight": {
+                                    "magnitude": 9525,
+                                    "unit": "EMU"
+                                },
+                                "dashStyle": "SOLID",
+                                "propertyState": "NOT_RENDERED"
+                            },
+                            "shadow": {
+                                "type": "OUTER",
+                                "transform": {
+                                    "scaleX": 1,
+                                    "scaleY": 1,
+                                    "unit": "EMU"
+                                },
+                                "alignment": "BOTTOM_LEFT",
+                                "blurRadius": {
+                                    "unit": "EMU"
+                                },
+                                "color": {
+                                    "rgbColor": {}
+                                },
+                                "alpha": 1,
+                                "rotateWithShape": false,
+                                "propertyState": "NOT_RENDERED"
+                            },
+                            "contentAlignment": "MIDDLE"
+                        }
+                    }
+                },
+                {
+                    "objectId": "p9_i1",
+                    "size": {
+                        "width": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        },
+                        "height": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        }
+                    },
+                    "transform": {
+                        "scaleX": 1.3484,
+                        "scaleY": 0.4941,
+                        "translateX": 265500,
+                        "translateY": 1233175,
+                        "unit": "EMU"
+                    },
+                    "shape": {
+                        "shapeType": "TEXT_BOX",
+                        "text": {
+                            "textElements": [
+                                {
+                                    "endIndex": 1,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "alignment": "CENTER",
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "endIndex": 1,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 42,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 1,
+                                    "endIndex": 2,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "alignment": "CENTER",
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 1,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 1,
+                                    "endIndex": 2,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 42,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 2,
+                                    "endIndex": 3,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "alignment": "CENTER",
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 2,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 2,
+                                    "endIndex": 3,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 42,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 3,
+                                    "endIndex": 4,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "alignment": "CENTER",
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 3,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 3,
+                                    "endIndex": 4,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 42,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 4,
+                                    "endIndex": 5,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "alignment": "CENTER",
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 4,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 4,
+                                    "endIndex": 5,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 42,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 5,
+                                    "endIndex": 6,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "alignment": "CENTER",
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 5,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 5,
+                                    "endIndex": 6,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 42,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 6,
+                                    "endIndex": 7,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "alignment": "CENTER",
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 6,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 6,
+                                    "endIndex": 7,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 42,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 7,
+                                    "endIndex": 8,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "alignment": "CENTER",
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 7,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 7,
+                                    "endIndex": 8,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 42,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 8,
+                                    "endIndex": 9,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "alignment": "CENTER",
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 8,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 8,
+                                    "endIndex": 9,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 42,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                }
+                            ],
+                            "lists": {
+                                "bodyPlaceholderListEntity": {
+                                    "listId": "bodyPlaceholderListEntity",
+                                    "nestingLevel": {
+                                        "0": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 42,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "1": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 42,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "2": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 42,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "3": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 42,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "4": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 42,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "5": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 42,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "6": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 42,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "7": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 42,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "8": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 42,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        },
+                        "shapeProperties": {
+                            "shapeBackgroundFill": {
+                                "propertyState": "INHERIT"
+                            },
+                            "outline": {
+                                "propertyState": "INHERIT"
+                            },
+                            "shadow": {
+                                "propertyState": "INHERIT"
+                            },
+                            "contentAlignment": "BOTTOM"
+                        },
+                        "placeholder": {
+                            "type": "TITLE",
+                            "parentObjectId": "p1_i0"
+                        }
+                    }
+                },
+                {
+                    "objectId": "p9_i2",
+                    "size": {
+                        "width": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        },
+                        "height": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        }
+                    },
+                    "transform": {
+                        "scaleX": 1.3484,
+                        "scaleY": 0.4117,
+                        "translateX": 265500,
+                        "translateY": 2803075,
+                        "unit": "EMU"
+                    },
+                    "shape": {
+                        "shapeType": "TEXT_BOX",
+                        "text": {
+                            "textElements": [
+                                {
+                                    "endIndex": 1,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "lineSpacing": 100,
+                                            "alignment": "CENTER",
+                                            "spaceBelow": {
+                                                "unit": "PT"
+                                            },
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "endIndex": 1,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 21,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 1,
+                                    "endIndex": 2,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "lineSpacing": 100,
+                                            "alignment": "CENTER",
+                                            "spaceBelow": {
+                                                "unit": "PT"
+                                            },
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 1,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 1,
+                                    "endIndex": 2,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 21,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 2,
+                                    "endIndex": 3,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "lineSpacing": 100,
+                                            "alignment": "CENTER",
+                                            "spaceBelow": {
+                                                "unit": "PT"
+                                            },
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 2,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 2,
+                                    "endIndex": 3,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 21,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 3,
+                                    "endIndex": 4,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "lineSpacing": 100,
+                                            "alignment": "CENTER",
+                                            "spaceBelow": {
+                                                "unit": "PT"
+                                            },
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 3,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 3,
+                                    "endIndex": 4,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 21,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 4,
+                                    "endIndex": 5,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "lineSpacing": 100,
+                                            "alignment": "CENTER",
+                                            "spaceBelow": {
+                                                "unit": "PT"
+                                            },
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 4,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 4,
+                                    "endIndex": 5,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 21,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 5,
+                                    "endIndex": 6,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "lineSpacing": 100,
+                                            "alignment": "CENTER",
+                                            "spaceBelow": {
+                                                "unit": "PT"
+                                            },
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 5,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 5,
+                                    "endIndex": 6,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 21,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 6,
+                                    "endIndex": 7,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "lineSpacing": 100,
+                                            "alignment": "CENTER",
+                                            "spaceBelow": {
+                                                "unit": "PT"
+                                            },
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 6,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 6,
+                                    "endIndex": 7,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 21,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 7,
+                                    "endIndex": 8,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "lineSpacing": 100,
+                                            "alignment": "CENTER",
+                                            "spaceBelow": {
+                                                "unit": "PT"
+                                            },
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 7,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 7,
+                                    "endIndex": 8,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 21,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 8,
+                                    "endIndex": 9,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "lineSpacing": 100,
+                                            "alignment": "CENTER",
+                                            "spaceBelow": {
+                                                "unit": "PT"
+                                            },
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 8,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 8,
+                                    "endIndex": 9,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 21,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                }
+                            ],
+                            "lists": {
+                                "bodyPlaceholderListEntity": {
+                                    "listId": "bodyPlaceholderListEntity",
+                                    "nestingLevel": {
+                                        "0": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 21,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "1": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 21,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "2": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 21,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "3": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 21,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "4": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 21,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "5": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 21,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "6": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 21,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "7": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 21,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "8": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 21,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        },
+                        "shapeProperties": {
+                            "shapeBackgroundFill": {
+                                "propertyState": "INHERIT"
+                            },
+                            "outline": {
+                                "propertyState": "INHERIT"
+                            },
+                            "shadow": {
+                                "propertyState": "INHERIT"
+                            }
+                        },
+                        "placeholder": {
+                            "type": "SUBTITLE",
+                            "parentObjectId": "p1_i1"
+                        }
+                    }
+                },
+                {
+                    "objectId": "p9_i3",
+                    "size": {
+                        "width": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        },
+                        "height": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        }
+                    },
+                    "transform": {
+                        "scaleX": 1.279,
+                        "scaleY": 1.2317,
+                        "translateX": 4939500,
+                        "translateY": 724075,
+                        "unit": "EMU"
+                    },
+                    "shape": {
+                        "shapeType": "TEXT_BOX",
+                        "text": {
+                            "textElements": [
+                                {
+                                    "endIndex": 1,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "glyph": "●",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "endIndex": 1,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {}
+                                    }
+                                },
+                                {
+                                    "startIndex": 1,
+                                    "endIndex": 2,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 1,
+                                            "glyph": "○",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 1,
+                                    "endIndex": 2,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {}
+                                    }
+                                },
+                                {
+                                    "startIndex": 2,
+                                    "endIndex": 3,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 2,
+                                            "glyph": "■",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 2,
+                                    "endIndex": 3,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {}
+                                    }
+                                },
+                                {
+                                    "startIndex": 3,
+                                    "endIndex": 4,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 3,
+                                            "glyph": "●",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 3,
+                                    "endIndex": 4,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {}
+                                    }
+                                },
+                                {
+                                    "startIndex": 4,
+                                    "endIndex": 5,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 4,
+                                            "glyph": "○",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 4,
+                                    "endIndex": 5,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {}
+                                    }
+                                },
+                                {
+                                    "startIndex": 5,
+                                    "endIndex": 6,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 5,
+                                            "glyph": "■",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 5,
+                                    "endIndex": 6,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {}
+                                    }
+                                },
+                                {
+                                    "startIndex": 6,
+                                    "endIndex": 7,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 6,
+                                            "glyph": "●",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 6,
+                                    "endIndex": 7,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {}
+                                    }
+                                },
+                                {
+                                    "startIndex": 7,
+                                    "endIndex": 8,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 7,
+                                            "glyph": "○",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 7,
+                                    "endIndex": 8,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {}
+                                    }
+                                },
+                                {
+                                    "startIndex": 8,
+                                    "endIndex": 9,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 8,
+                                            "glyph": "■",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 8,
+                                    "endIndex": 9,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {}
+                                    }
+                                }
+                            ],
+                            "lists": {
+                                "bodyPlaceholderListEntity": {
+                                    "listId": "bodyPlaceholderListEntity",
+                                    "nestingLevel": {
+                                        "0": {
+                                            "bulletStyle": {}
+                                        },
+                                        "1": {
+                                            "bulletStyle": {}
+                                        },
+                                        "2": {
+                                            "bulletStyle": {}
+                                        },
+                                        "3": {
+                                            "bulletStyle": {}
+                                        },
+                                        "4": {
+                                            "bulletStyle": {}
+                                        },
+                                        "5": {
+                                            "bulletStyle": {}
+                                        },
+                                        "6": {
+                                            "bulletStyle": {}
+                                        },
+                                        "7": {
+                                            "bulletStyle": {}
+                                        },
+                                        "8": {
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                }
+                            }
+                        },
+                        "shapeProperties": {
+                            "shapeBackgroundFill": {
+                                "propertyState": "INHERIT"
+                            },
+                            "outline": {
+                                "propertyState": "INHERIT"
+                            },
+                            "shadow": {
+                                "propertyState": "INHERIT"
+                            },
+                            "contentAlignment": "MIDDLE"
+                        },
+                        "placeholder": {
+                            "type": "BODY",
+                            "parentObjectId": "p1_i1"
+                        }
+                    }
+                },
+                {
+                    "objectId": "p9_i4",
+                    "size": {
+                        "width": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        },
+                        "height": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        }
+                    },
+                    "transform": {
+                        "scaleX": 0.1829,
+                        "scaleY": 0.1312,
+                        "translateX": 8472457.8125,
+                        "translateY": 4663216.797499999,
+                        "unit": "EMU"
+                    },
+                    "shape": {
+                        "shapeType": "TEXT_BOX",
+                        "text": {
+                            "textElements": [
+                                {
+                                    "endIndex": 2,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        }
+                                    }
+                                },
+                                {
+                                    "endIndex": 1,
+                                    "autoText": {
+                                        "type": "SLIDE_NUMBER",
+                                        "content": "#",
+                                        "style": {}
+                                    }
+                                },
+                                {
+                                    "startIndex": 1,
+                                    "endIndex": 2,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {}
+                                    }
+                                }
+                            ]
+                        },
+                        "shapeProperties": {
+                            "shapeBackgroundFill": {
+                                "propertyState": "INHERIT"
+                            },
+                            "outline": {
+                                "propertyState": "INHERIT"
+                            },
+                            "shadow": {
+                                "propertyState": "INHERIT"
+                            }
+                        },
+                        "placeholder": {
+                            "type": "SLIDE_NUMBER",
+                            "parentObjectId": "p1_i2"
+                        }
+                    }
+                }
+            ],
+            "layoutProperties": {
+                "masterObjectId": "simple-light-2",
+                "name": "SECTION_TITLE_AND_DESCRIPTION",
+                "displayName": "Section title and description"
+            },
+            "pageProperties": {
+                "pageBackgroundFill": {
+                    "propertyState": "INHERIT"
+                }
+            }
+        },
+        {
+            "objectId": "p10",
+            "pageType": "LAYOUT",
+            "pageElements": [
+                {
+                    "objectId": "p10_i0",
+                    "size": {
+                        "width": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        },
+                        "height": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        }
+                    },
+                    "transform": {
+                        "scaleX": 1.9996,
+                        "scaleY": 0.2017,
+                        "translateX": 311700,
+                        "translateY": 4230575,
+                        "unit": "EMU"
+                    },
+                    "shape": {
+                        "shapeType": "TEXT_BOX",
+                        "text": {
+                            "textElements": [
+                                {
+                                    "endIndex": 1,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "lineSpacing": 100,
+                                            "spaceBelow": {
+                                                "unit": "PT"
+                                            },
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "endIndex": 1,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {}
+                                    }
+                                }
+                            ],
+                            "lists": {
+                                "bodyPlaceholderListEntity": {
+                                    "listId": "bodyPlaceholderListEntity",
+                                    "nestingLevel": {
+                                        "0": {
+                                            "bulletStyle": {}
+                                        },
+                                        "1": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 18,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "2": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 18,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "3": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 18,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "4": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 18,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "5": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 18,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "6": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 18,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "7": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 18,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "8": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 18,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        },
+                        "shapeProperties": {
+                            "shapeBackgroundFill": {
+                                "propertyState": "INHERIT"
+                            },
+                            "outline": {
+                                "propertyState": "INHERIT"
+                            },
+                            "shadow": {
+                                "propertyState": "INHERIT"
+                            },
+                            "contentAlignment": "MIDDLE"
+                        },
+                        "placeholder": {
+                            "type": "BODY",
+                            "parentObjectId": "p1_i1"
+                        }
+                    }
+                },
+                {
+                    "objectId": "p10_i1",
+                    "size": {
+                        "width": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        },
+                        "height": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        }
+                    },
+                    "transform": {
+                        "scaleX": 0.1829,
+                        "scaleY": 0.1312,
+                        "translateX": 8472457.8125,
+                        "translateY": 4663216.797499999,
+                        "unit": "EMU"
+                    },
+                    "shape": {
+                        "shapeType": "TEXT_BOX",
+                        "text": {
+                            "textElements": [
+                                {
+                                    "endIndex": 2,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        }
+                                    }
+                                },
+                                {
+                                    "endIndex": 1,
+                                    "autoText": {
+                                        "type": "SLIDE_NUMBER",
+                                        "content": "#",
+                                        "style": {}
+                                    }
+                                },
+                                {
+                                    "startIndex": 1,
+                                    "endIndex": 2,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {}
+                                    }
+                                }
+                            ]
+                        },
+                        "shapeProperties": {
+                            "shapeBackgroundFill": {
+                                "propertyState": "INHERIT"
+                            },
+                            "outline": {
+                                "propertyState": "INHERIT"
+                            },
+                            "shadow": {
+                                "propertyState": "INHERIT"
+                            }
+                        },
+                        "placeholder": {
+                            "type": "SLIDE_NUMBER",
+                            "parentObjectId": "p1_i2"
+                        }
+                    }
+                }
+            ],
+            "layoutProperties": {
+                "masterObjectId": "simple-light-2",
+                "name": "CAPTION_ONLY",
+                "displayName": "Caption"
+            },
+            "pageProperties": {
+                "pageBackgroundFill": {
+                    "propertyState": "INHERIT"
+                }
+            }
+        },
+        {
+            "objectId": "p11",
+            "pageType": "LAYOUT",
+            "pageElements": [
+                {
+                    "objectId": "p11_i0",
+                    "size": {
+                        "width": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        },
+                        "height": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        }
+                    },
+                    "transform": {
+                        "scaleX": 2.8402,
+                        "scaleY": 0.6545,
+                        "translateX": 311700,
+                        "translateY": 1106125,
+                        "unit": "EMU"
+                    },
+                    "shape": {
+                        "shapeType": "TEXT_BOX",
+                        "text": {
+                            "textElements": [
+                                {
+                                    "endIndex": 1,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "alignment": "CENTER",
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "endIndex": 1,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 120,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 1,
+                                    "endIndex": 2,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "alignment": "CENTER",
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 1,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 1,
+                                    "endIndex": 2,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 120,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 2,
+                                    "endIndex": 3,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "alignment": "CENTER",
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 2,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 2,
+                                    "endIndex": 3,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 120,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 3,
+                                    "endIndex": 4,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "alignment": "CENTER",
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 3,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 3,
+                                    "endIndex": 4,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 120,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 4,
+                                    "endIndex": 5,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "alignment": "CENTER",
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 4,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 4,
+                                    "endIndex": 5,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 120,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 5,
+                                    "endIndex": 6,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "alignment": "CENTER",
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 5,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 5,
+                                    "endIndex": 6,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 120,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 6,
+                                    "endIndex": 7,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "alignment": "CENTER",
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 6,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 6,
+                                    "endIndex": 7,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 120,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 7,
+                                    "endIndex": 8,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "alignment": "CENTER",
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 7,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 7,
+                                    "endIndex": 8,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 120,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 8,
+                                    "endIndex": 9,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "alignment": "CENTER",
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 8,
+                                            "glyph": " ",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 8,
+                                    "endIndex": 9,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {
+                                            "fontSize": {
+                                                "magnitude": 120,
+                                                "unit": "PT"
+                                            }
+                                        }
+                                    }
+                                }
+                            ],
+                            "lists": {
+                                "bodyPlaceholderListEntity": {
+                                    "listId": "bodyPlaceholderListEntity",
+                                    "nestingLevel": {
+                                        "0": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 120,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "1": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 120,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "2": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 120,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "3": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 120,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "4": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 120,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "5": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 120,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "6": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 120,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "7": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 120,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        },
+                                        "8": {
+                                            "bulletStyle": {
+                                                "fontSize": {
+                                                    "magnitude": 120,
+                                                    "unit": "PT"
+                                                }
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        },
+                        "shapeProperties": {
+                            "shapeBackgroundFill": {
+                                "propertyState": "INHERIT"
+                            },
+                            "outline": {
+                                "propertyState": "INHERIT"
+                            },
+                            "shadow": {
+                                "propertyState": "INHERIT"
+                            },
+                            "contentAlignment": "BOTTOM"
+                        },
+                        "placeholder": {
+                            "type": "TITLE",
+                            "parentObjectId": "p1_i0"
+                        }
+                    }
+                },
+                {
+                    "objectId": "p11_i1",
+                    "size": {
+                        "width": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        },
+                        "height": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        }
+                    },
+                    "transform": {
+                        "scaleX": 2.8402,
+                        "scaleY": 0.4336,
+                        "translateX": 311700,
+                        "translateY": 3152225,
+                        "unit": "EMU"
+                    },
+                    "shape": {
+                        "shapeType": "TEXT_BOX",
+                        "text": {
+                            "textElements": [
+                                {
+                                    "endIndex": 1,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "alignment": "CENTER",
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "glyph": "●",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "endIndex": 1,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {}
+                                    }
+                                },
+                                {
+                                    "startIndex": 1,
+                                    "endIndex": 2,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "alignment": "CENTER",
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 1,
+                                            "glyph": "○",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 1,
+                                    "endIndex": 2,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {}
+                                    }
+                                },
+                                {
+                                    "startIndex": 2,
+                                    "endIndex": 3,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "alignment": "CENTER",
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 2,
+                                            "glyph": "■",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 2,
+                                    "endIndex": 3,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {}
+                                    }
+                                },
+                                {
+                                    "startIndex": 3,
+                                    "endIndex": 4,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "alignment": "CENTER",
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 3,
+                                            "glyph": "●",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 3,
+                                    "endIndex": 4,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {}
+                                    }
+                                },
+                                {
+                                    "startIndex": 4,
+                                    "endIndex": 5,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "alignment": "CENTER",
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 4,
+                                            "glyph": "○",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 4,
+                                    "endIndex": 5,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {}
+                                    }
+                                },
+                                {
+                                    "startIndex": 5,
+                                    "endIndex": 6,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "alignment": "CENTER",
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 5,
+                                            "glyph": "■",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 5,
+                                    "endIndex": 6,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {}
+                                    }
+                                },
+                                {
+                                    "startIndex": 6,
+                                    "endIndex": 7,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "alignment": "CENTER",
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 6,
+                                            "glyph": "●",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 6,
+                                    "endIndex": 7,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {}
+                                    }
+                                },
+                                {
+                                    "startIndex": 7,
+                                    "endIndex": 8,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "alignment": "CENTER",
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 7,
+                                            "glyph": "○",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 7,
+                                    "endIndex": 8,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {}
+                                    }
+                                },
+                                {
+                                    "startIndex": 8,
+                                    "endIndex": 9,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "alignment": "CENTER",
+                                            "direction": "LEFT_TO_RIGHT"
+                                        },
+                                        "bullet": {
+                                            "listId": "bodyPlaceholderListEntity",
+                                            "nestingLevel": 8,
+                                            "glyph": "■",
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                },
+                                {
+                                    "startIndex": 8,
+                                    "endIndex": 9,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {}
+                                    }
+                                }
+                            ],
+                            "lists": {
+                                "bodyPlaceholderListEntity": {
+                                    "listId": "bodyPlaceholderListEntity",
+                                    "nestingLevel": {
+                                        "0": {
+                                            "bulletStyle": {}
+                                        },
+                                        "1": {
+                                            "bulletStyle": {}
+                                        },
+                                        "2": {
+                                            "bulletStyle": {}
+                                        },
+                                        "3": {
+                                            "bulletStyle": {}
+                                        },
+                                        "4": {
+                                            "bulletStyle": {}
+                                        },
+                                        "5": {
+                                            "bulletStyle": {}
+                                        },
+                                        "6": {
+                                            "bulletStyle": {}
+                                        },
+                                        "7": {
+                                            "bulletStyle": {}
+                                        },
+                                        "8": {
+                                            "bulletStyle": {}
+                                        }
+                                    }
+                                }
+                            }
+                        },
+                        "shapeProperties": {
+                            "shapeBackgroundFill": {
+                                "propertyState": "INHERIT"
+                            },
+                            "outline": {
+                                "propertyState": "INHERIT"
+                            },
+                            "shadow": {
+                                "propertyState": "INHERIT"
+                            }
+                        },
+                        "placeholder": {
+                            "type": "BODY",
+                            "parentObjectId": "p1_i1"
+                        }
+                    }
+                },
+                {
+                    "objectId": "p11_i2",
+                    "size": {
+                        "width": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        },
+                        "height": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        }
+                    },
+                    "transform": {
+                        "scaleX": 0.1829,
+                        "scaleY": 0.1312,
+                        "translateX": 8472457.8125,
+                        "translateY": 4663216.797499999,
+                        "unit": "EMU"
+                    },
+                    "shape": {
+                        "shapeType": "TEXT_BOX",
+                        "text": {
+                            "textElements": [
+                                {
+                                    "endIndex": 2,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        }
+                                    }
+                                },
+                                {
+                                    "endIndex": 1,
+                                    "autoText": {
+                                        "type": "SLIDE_NUMBER",
+                                        "content": "#",
+                                        "style": {}
+                                    }
+                                },
+                                {
+                                    "startIndex": 1,
+                                    "endIndex": 2,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {}
+                                    }
+                                }
+                            ]
+                        },
+                        "shapeProperties": {
+                            "shapeBackgroundFill": {
+                                "propertyState": "INHERIT"
+                            },
+                            "outline": {
+                                "propertyState": "INHERIT"
+                            },
+                            "shadow": {
+                                "propertyState": "INHERIT"
+                            }
+                        },
+                        "placeholder": {
+                            "type": "SLIDE_NUMBER",
+                            "parentObjectId": "p1_i2"
+                        }
+                    }
+                }
+            ],
+            "layoutProperties": {
+                "masterObjectId": "simple-light-2",
+                "name": "BIG_NUMBER",
+                "displayName": "Big number"
+            },
+            "pageProperties": {
+                "pageBackgroundFill": {
+                    "propertyState": "INHERIT"
+                }
+            }
+        },
+        {
+            "objectId": "p12",
+            "pageType": "LAYOUT",
+            "pageElements": [
+                {
+                    "objectId": "p12_i0",
+                    "size": {
+                        "width": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        },
+                        "height": {
+                            "magnitude": 3000000,
+                            "unit": "EMU"
+                        }
+                    },
+                    "transform": {
+                        "scaleX": 0.1829,
+                        "scaleY": 0.1312,
+                        "translateX": 8472457.8125,
+                        "translateY": 4663216.797499999,
+                        "unit": "EMU"
+                    },
+                    "shape": {
+                        "shapeType": "TEXT_BOX",
+                        "text": {
+                            "textElements": [
+                                {
+                                    "endIndex": 2,
+                                    "paragraphMarker": {
+                                        "style": {
+                                            "direction": "LEFT_TO_RIGHT"
+                                        }
+                                    }
+                                },
+                                {
+                                    "endIndex": 1,
+                                    "autoText": {
+                                        "type": "SLIDE_NUMBER",
+                                        "content": "#",
+                                        "style": {}
+                                    }
+                                },
+                                {
+                                    "startIndex": 1,
+                                    "endIndex": 2,
+                                    "textRun": {
+                                        "content": "\n",
+                                        "style": {}
+                                    }
+                                }
+                            ]
+                        },
+                        "shapeProperties": {
+                            "shapeBackgroundFill": {
+                                "propertyState": "INHERIT"
+                            },
+                            "outline": {
+                                "propertyState": "INHERIT"
+                            },
+                            "shadow": {
+                                "propertyState": "INHERIT"
+                            }
+                        },
+                        "placeholder": {
+                            "type": "SLIDE_NUMBER",
+                            "parentObjectId": "p1_i2"
+                        }
+                    }
+                }
+            ],
+            "layoutProperties": {
+                "masterObjectId": "simple-light-2",
+                "name": "BLANK",
+                "displayName": "Blank"
+            },
+            "pageProperties": {
+                "pageBackgroundFill": {
+                    "propertyState": "INHERIT"
+                }
+            }
+        }
+    ],
+    "locale": "en",
+    "revisionId": "kaHql7SEgvqFcw",
+    "notesMaster": {
+        "objectId": "n",
+        "pageType": "NOTES_MASTER",
+        "pageElements": [
+            {
+                "objectId": "n:slide",
+                "size": {
+                    "width": {
+                        "magnitude": 3000000,
+                        "unit": "EMU"
+                    },
+                    "height": {
+                        "magnitude": 3000000,
+                        "unit": "EMU"
+                    }
+                },
+                "transform": {
+                    "scaleX": 2.032025,
+                    "scaleY": 1.143,
+                    "translateX": 381300,
+                    "translateY": 685800,
+                    "unit": "EMU"
+                },
+                "shape": {
+                    "shapeProperties": {
+                        "outline": {
+                            "outlineFill": {
+                                "solidFill": {
+                                    "color": {
+                                        "rgbColor": {}
+                                    },
+                                    "alpha": 1
+                                }
+                            },
+                            "weight": {
+                                "magnitude": 9525,
+                                "unit": "EMU"
+                            },
+                            "dashStyle": "SOLID"
+                        },
+                        "contentAlignment": "MIDDLE"
+                    },
+                    "placeholder": {
+                        "type": "SLIDE_IMAGE"
+                    }
+                }
+            },
+            {
+                "objectId": "n:text",
+                "size": {
+                    "width": {
+                        "magnitude": 3000000,
+                        "unit": "EMU"
+                    },
+                    "height": {
+                        "magnitude": 3000000,
+                        "unit": "EMU"
+                    }
+                },
+                "transform": {
+                    "scaleX": 1.8288,
+                    "scaleY": 1.3716,
+                    "translateX": 685800,
+                    "translateY": 4343400,
+                    "unit": "EMU"
+                },
+                "shape": {
+                    "shapeType": "TEXT_BOX",
+                    "text": {
+                        "textElements": [
+                            {
+                                "endIndex": 1,
+                                "paragraphMarker": {
+                                    "style": {
+                                        "lineSpacing": 100,
+                                        "alignment": "START",
+                                        "indentStart": {
+                                            "unit": "PT"
+                                        },
+                                        "indentEnd": {
+                                            "unit": "PT"
+                                        },
+                                        "spaceAbove": {
+                                            "unit": "PT"
+                                        },
+                                        "spaceBelow": {
+                                            "unit": "PT"
+                                        },
+                                        "indentFirstLine": {
+                                            "unit": "PT"
+                                        },
+                                        "direction": "LEFT_TO_RIGHT",
+                                        "spacingMode": "COLLAPSE_LISTS"
+                                    },
+                                    "bullet": {
+                                        "listId": "bodyPlaceholderListEntity",
+                                        "glyph": "●",
+                                        "bulletStyle": {}
+                                    }
+                                }
+                            },
+                            {
+                                "endIndex": 1,
+                                "textRun": {
+                                    "content": "\n",
+                                    "style": {
+                                        "backgroundColor": {},
+                                        "foregroundColor": {
+                                            "opaqueColor": {
+                                                "rgbColor": {}
+                                            }
+                                        },
+                                        "bold": false,
+                                        "italic": false,
+                                        "fontFamily": "Arial",
+                                        "fontSize": {
+                                            "magnitude": 11,
+                                            "unit": "PT"
+                                        },
+                                        "baselineOffset": "NONE",
+                                        "smallCaps": false,
+                                        "strikethrough": false,
+                                        "underline": false,
+                                        "weightedFontFamily": {
+                                            "fontFamily": "Arial",
+                                            "weight": 400
+                                        }
+                                    }
+                                }
+                            },
+                            {
+                                "startIndex": 1,
+                                "endIndex": 2,
+                                "paragraphMarker": {
+                                    "style": {
+                                        "lineSpacing": 100,
+                                        "alignment": "START",
+                                        "indentStart": {
+                                            "unit": "PT"
+                                        },
+                                        "indentEnd": {
+                                            "unit": "PT"
+                                        },
+                                        "spaceAbove": {
+                                            "unit": "PT"
+                                        },
+                                        "spaceBelow": {
+                                            "unit": "PT"
+                                        },
+                                        "indentFirstLine": {
+                                            "unit": "PT"
+                                        },
+                                        "direction": "LEFT_TO_RIGHT",
+                                        "spacingMode": "COLLAPSE_LISTS"
+                                    },
+                                    "bullet": {
+                                        "listId": "bodyPlaceholderListEntity",
+                                        "nestingLevel": 1,
+                                        "glyph": "○",
+                                        "bulletStyle": {}
+                                    }
+                                }
+                            },
+                            {
+                                "startIndex": 1,
+                                "endIndex": 2,
+                                "textRun": {
+                                    "content": "\n",
+                                    "style": {
+                                        "backgroundColor": {},
+                                        "foregroundColor": {
+                                            "opaqueColor": {
+                                                "rgbColor": {}
+                                            }
+                                        },
+                                        "bold": false,
+                                        "italic": false,
+                                        "fontFamily": "Arial",
+                                        "fontSize": {
+                                            "magnitude": 11,
+                                            "unit": "PT"
+                                        },
+                                        "baselineOffset": "NONE",
+                                        "smallCaps": false,
+                                        "strikethrough": false,
+                                        "underline": false,
+                                        "weightedFontFamily": {
+                                            "fontFamily": "Arial",
+                                            "weight": 400
+                                        }
+                                    }
+                                }
+                            },
+                            {
+                                "startIndex": 2,
+                                "endIndex": 3,
+                                "paragraphMarker": {
+                                    "style": {
+                                        "lineSpacing": 100,
+                                        "alignment": "START",
+                                        "indentStart": {
+                                            "unit": "PT"
+                                        },
+                                        "indentEnd": {
+                                            "unit": "PT"
+                                        },
+                                        "spaceAbove": {
+                                            "unit": "PT"
+                                        },
+                                        "spaceBelow": {
+                                            "unit": "PT"
+                                        },
+                                        "indentFirstLine": {
+                                            "unit": "PT"
+                                        },
+                                        "direction": "LEFT_TO_RIGHT",
+                                        "spacingMode": "COLLAPSE_LISTS"
+                                    },
+                                    "bullet": {
+                                        "listId": "bodyPlaceholderListEntity",
+                                        "nestingLevel": 2,
+                                        "glyph": "■",
+                                        "bulletStyle": {}
+                                    }
+                                }
+                            },
+                            {
+                                "startIndex": 2,
+                                "endIndex": 3,
+                                "textRun": {
+                                    "content": "\n",
+                                    "style": {
+                                        "backgroundColor": {},
+                                        "foregroundColor": {
+                                            "opaqueColor": {
+                                                "rgbColor": {}
+                                            }
+                                        },
+                                        "bold": false,
+                                        "italic": false,
+                                        "fontFamily": "Arial",
+                                        "fontSize": {
+                                            "magnitude": 11,
+                                            "unit": "PT"
+                                        },
+                                        "baselineOffset": "NONE",
+                                        "smallCaps": false,
+                                        "strikethrough": false,
+                                        "underline": false,
+                                        "weightedFontFamily": {
+                                            "fontFamily": "Arial",
+                                            "weight": 400
+                                        }
+                                    }
+                                }
+                            },
+                            {
+                                "startIndex": 3,
+                                "endIndex": 4,
+                                "paragraphMarker": {
+                                    "style": {
+                                        "lineSpacing": 100,
+                                        "alignment": "START",
+                                        "indentStart": {
+                                            "unit": "PT"
+                                        },
+                                        "indentEnd": {
+                                            "unit": "PT"
+                                        },
+                                        "spaceAbove": {
+                                            "unit": "PT"
+                                        },
+                                        "spaceBelow": {
+                                            "unit": "PT"
+                                        },
+                                        "indentFirstLine": {
+                                            "unit": "PT"
+                                        },
+                                        "direction": "LEFT_TO_RIGHT",
+                                        "spacingMode": "COLLAPSE_LISTS"
+                                    },
+                                    "bullet": {
+                                        "listId": "bodyPlaceholderListEntity",
+                                        "nestingLevel": 3,
+                                        "glyph": "●",
+                                        "bulletStyle": {}
+                                    }
+                                }
+                            },
+                            {
+                                "startIndex": 3,
+                                "endIndex": 4,
+                                "textRun": {
+                                    "content": "\n",
+                                    "style": {
+                                        "backgroundColor": {},
+                                        "foregroundColor": {
+                                            "opaqueColor": {
+                                                "rgbColor": {}
+                                            }
+                                        },
+                                        "bold": false,
+                                        "italic": false,
+                                        "fontFamily": "Arial",
+                                        "fontSize": {
+                                            "magnitude": 11,
+                                            "unit": "PT"
+                                        },
+                                        "baselineOffset": "NONE",
+                                        "smallCaps": false,
+                                        "strikethrough": false,
+                                        "underline": false,
+                                        "weightedFontFamily": {
+                                            "fontFamily": "Arial",
+                                            "weight": 400
+                                        }
+                                    }
+                                }
+                            },
+                            {
+                                "startIndex": 4,
+                                "endIndex": 5,
+                                "paragraphMarker": {
+                                    "style": {
+                                        "lineSpacing": 100,
+                                        "alignment": "START",
+                                        "indentStart": {
+                                            "unit": "PT"
+                                        },
+                                        "indentEnd": {
+                                            "unit": "PT"
+                                        },
+                                        "spaceAbove": {
+                                            "unit": "PT"
+                                        },
+                                        "spaceBelow": {
+                                            "unit": "PT"
+                                        },
+                                        "indentFirstLine": {
+                                            "unit": "PT"
+                                        },
+                                        "direction": "LEFT_TO_RIGHT",
+                                        "spacingMode": "COLLAPSE_LISTS"
+                                    },
+                                    "bullet": {
+                                        "listId": "bodyPlaceholderListEntity",
+                                        "nestingLevel": 4,
+                                        "glyph": "○",
+                                        "bulletStyle": {}
+                                    }
+                                }
+                            },
+                            {
+                                "startIndex": 4,
+                                "endIndex": 5,
+                                "textRun": {
+                                    "content": "\n",
+                                    "style": {
+                                        "backgroundColor": {},
+                                        "foregroundColor": {
+                                            "opaqueColor": {
+                                                "rgbColor": {}
+                                            }
+                                        },
+                                        "bold": false,
+                                        "italic": false,
+                                        "fontFamily": "Arial",
+                                        "fontSize": {
+                                            "magnitude": 11,
+                                            "unit": "PT"
+                                        },
+                                        "baselineOffset": "NONE",
+                                        "smallCaps": false,
+                                        "strikethrough": false,
+                                        "underline": false,
+                                        "weightedFontFamily": {
+                                            "fontFamily": "Arial",
+                                            "weight": 400
+                                        }
+                                    }
+                                }
+                            },
+                            {
+                                "startIndex": 5,
+                                "endIndex": 6,
+                                "paragraphMarker": {
+                                    "style": {
+                                        "lineSpacing": 100,
+                                        "alignment": "START",
+                                        "indentStart": {
+                                            "unit": "PT"
+                                        },
+                                        "indentEnd": {
+                                            "unit": "PT"
+                                        },
+                                        "spaceAbove": {
+                                            "unit": "PT"
+                                        },
+                                        "spaceBelow": {
+                                            "unit": "PT"
+                                        },
+                                        "indentFirstLine": {
+                                            "unit": "PT"
+                                        },
+                                        "direction": "LEFT_TO_RIGHT",
+                                        "spacingMode": "COLLAPSE_LISTS"
+                                    },
+                                    "bullet": {
+                                        "listId": "bodyPlaceholderListEntity",
+                                        "nestingLevel": 5,
+                                        "glyph": "■",
+                                        "bulletStyle": {}
+                                    }
+                                }
+                            },
+                            {
+                                "startIndex": 5,
+                                "endIndex": 6,
+                                "textRun": {
+                                    "content": "\n",
+                                    "style": {
+                                        "backgroundColor": {},
+                                        "foregroundColor": {
+                                            "opaqueColor": {
+                                                "rgbColor": {}
+                                            }
+                                        },
+                                        "bold": false,
+                                        "italic": false,
+                                        "fontFamily": "Arial",
+                                        "fontSize": {
+                                            "magnitude": 11,
+                                            "unit": "PT"
+                                        },
+                                        "baselineOffset": "NONE",
+                                        "smallCaps": false,
+                                        "strikethrough": false,
+                                        "underline": false,
+                                        "weightedFontFamily": {
+                                            "fontFamily": "Arial",
+                                            "weight": 400
+                                        }
+                                    }
+                                }
+                            },
+                            {
+                                "startIndex": 6,
+                                "endIndex": 7,
+                                "paragraphMarker": {
+                                    "style": {
+                                        "lineSpacing": 100,
+                                        "alignment": "START",
+                                        "indentStart": {
+                                            "unit": "PT"
+                                        },
+                                        "indentEnd": {
+                                            "unit": "PT"
+                                        },
+                                        "spaceAbove": {
+                                            "unit": "PT"
+                                        },
+                                        "spaceBelow": {
+                                            "unit": "PT"
+                                        },
+                                        "indentFirstLine": {
+                                            "unit": "PT"
+                                        },
+                                        "direction": "LEFT_TO_RIGHT",
+                                        "spacingMode": "COLLAPSE_LISTS"
+                                    },
+                                    "bullet": {
+                                        "listId": "bodyPlaceholderListEntity",
+                                        "nestingLevel": 6,
+                                        "glyph": "●",
+                                        "bulletStyle": {}
+                                    }
+                                }
+                            },
+                            {
+                                "startIndex": 6,
+                                "endIndex": 7,
+                                "textRun": {
+                                    "content": "\n",
+                                    "style": {
+                                        "backgroundColor": {},
+                                        "foregroundColor": {
+                                            "opaqueColor": {
+                                                "rgbColor": {}
+                                            }
+                                        },
+                                        "bold": false,
+                                        "italic": false,
+                                        "fontFamily": "Arial",
+                                        "fontSize": {
+                                            "magnitude": 11,
+                                            "unit": "PT"
+                                        },
+                                        "baselineOffset": "NONE",
+                                        "smallCaps": false,
+                                        "strikethrough": false,
+                                        "underline": false,
+                                        "weightedFontFamily": {
+                                            "fontFamily": "Arial",
+                                            "weight": 400
+                                        }
+                                    }
+                                }
+                            },
+                            {
+                                "startIndex": 7,
+                                "endIndex": 8,
+                                "paragraphMarker": {
+                                    "style": {
+                                        "lineSpacing": 100,
+                                        "alignment": "START",
+                                        "indentStart": {
+                                            "unit": "PT"
+                                        },
+                                        "indentEnd": {
+                                            "unit": "PT"
+                                        },
+                                        "spaceAbove": {
+                                            "unit": "PT"
+                                        },
+                                        "spaceBelow": {
+                                            "unit": "PT"
+                                        },
+                                        "indentFirstLine": {
+                                            "unit": "PT"
+                                        },
+                                        "direction": "LEFT_TO_RIGHT",
+                                        "spacingMode": "COLLAPSE_LISTS"
+                                    },
+                                    "bullet": {
+                                        "listId": "bodyPlaceholderListEntity",
+                                        "nestingLevel": 7,
+                                        "glyph": "○",
+                                        "bulletStyle": {}
+                                    }
+                                }
+                            },
+                            {
+                                "startIndex": 7,
+                                "endIndex": 8,
+                                "textRun": {
+                                    "content": "\n",
+                                    "style": {
+                                        "backgroundColor": {},
+                                        "foregroundColor": {
+                                            "opaqueColor": {
+                                                "rgbColor": {}
+                                            }
+                                        },
+                                        "bold": false,
+                                        "italic": false,
+                                        "fontFamily": "Arial",
+                                        "fontSize": {
+                                            "magnitude": 11,
+                                            "unit": "PT"
+                                        },
+                                        "baselineOffset": "NONE",
+                                        "smallCaps": false,
+                                        "strikethrough": false,
+                                        "underline": false,
+                                        "weightedFontFamily": {
+                                            "fontFamily": "Arial",
+                                            "weight": 400
+                                        }
+                                    }
+                                }
+                            },
+                            {
+                                "startIndex": 8,
+                                "endIndex": 9,
+                                "paragraphMarker": {
+                                    "style": {
+                                        "lineSpacing": 100,
+                                        "alignment": "START",
+                                        "indentStart": {
+                                            "unit": "PT"
+                                        },
+                                        "indentEnd": {
+                                            "unit": "PT"
+                                        },
+                                        "spaceAbove": {
+                                            "unit": "PT"
+                                        },
+                                        "spaceBelow": {
+                                            "unit": "PT"
+                                        },
+                                        "indentFirstLine": {
+                                            "unit": "PT"
+                                        },
+                                        "direction": "LEFT_TO_RIGHT",
+                                        "spacingMode": "COLLAPSE_LISTS"
+                                    },
+                                    "bullet": {
+                                        "listId": "bodyPlaceholderListEntity",
+                                        "nestingLevel": 8,
+                                        "glyph": "■",
+                                        "bulletStyle": {}
+                                    }
+                                }
+                            },
+                            {
+                                "startIndex": 8,
+                                "endIndex": 9,
+                                "textRun": {
+                                    "content": "\n",
+                                    "style": {
+                                        "backgroundColor": {},
+                                        "foregroundColor": {
+                                            "opaqueColor": {
+                                                "rgbColor": {}
+                                            }
+                                        },
+                                        "bold": false,
+                                        "italic": false,
+                                        "fontFamily": "Arial",
+                                        "fontSize": {
+                                            "magnitude": 11,
+                                            "unit": "PT"
+                                        },
+                                        "baselineOffset": "NONE",
+                                        "smallCaps": false,
+                                        "strikethrough": false,
+                                        "underline": false,
+                                        "weightedFontFamily": {
+                                            "fontFamily": "Arial",
+                                            "weight": 400
+                                        }
+                                    }
+                                }
+                            }
+                        ],
+                        "lists": {
+                            "bodyPlaceholderListEntity": {
+                                "listId": "bodyPlaceholderListEntity",
+                                "nestingLevel": {
+                                    "0": {
+                                        "bulletStyle": {
+                                            "backgroundColor": {},
+                                            "foregroundColor": {
+                                                "opaqueColor": {
+                                                    "rgbColor": {}
+                                                }
+                                            },
+                                            "bold": false,
+                                            "italic": false,
+                                            "fontFamily": "Arial",
+                                            "fontSize": {
+                                                "magnitude": 11,
+                                                "unit": "PT"
+                                            },
+                                            "baselineOffset": "NONE",
+                                            "smallCaps": false,
+                                            "strikethrough": false,
+                                            "underline": false,
+                                            "weightedFontFamily": {
+                                                "fontFamily": "Arial",
+                                                "weight": 400
+                                            }
+                                        }
+                                    },
+                                    "1": {
+                                        "bulletStyle": {
+                                            "backgroundColor": {},
+                                            "foregroundColor": {
+                                                "opaqueColor": {
+                                                    "rgbColor": {}
+                                                }
+                                            },
+                                            "bold": false,
+                                            "italic": false,
+                                            "fontFamily": "Arial",
+                                            "fontSize": {
+                                                "magnitude": 11,
+                                                "unit": "PT"
+                                            },
+                                            "baselineOffset": "NONE",
+                                            "smallCaps": false,
+                                            "strikethrough": false,
+                                            "underline": false,
+                                            "weightedFontFamily": {
+                                                "fontFamily": "Arial",
+                                                "weight": 400
+                                            }
+                                        }
+                                    },
+                                    "2": {
+                                        "bulletStyle": {
+                                            "backgroundColor": {},
+                                            "foregroundColor": {
+                                                "opaqueColor": {
+                                                    "rgbColor": {}
+                                                }
+                                            },
+                                            "bold": false,
+                                            "italic": false,
+                                            "fontFamily": "Arial",
+                                            "fontSize": {
+                                                "magnitude": 11,
+                                                "unit": "PT"
+                                            },
+                                            "baselineOffset": "NONE",
+                                            "smallCaps": false,
+                                            "strikethrough": false,
+                                            "underline": false,
+                                            "weightedFontFamily": {
+                                                "fontFamily": "Arial",
+                                                "weight": 400
+                                            }
+                                        }
+                                    },
+                                    "3": {
+                                        "bulletStyle": {
+                                            "backgroundColor": {},
+                                            "foregroundColor": {
+                                                "opaqueColor": {
+                                                    "rgbColor": {}
+                                                }
+                                            },
+                                            "bold": false,
+                                            "italic": false,
+                                            "fontFamily": "Arial",
+                                            "fontSize": {
+                                                "magnitude": 11,
+                                                "unit": "PT"
+                                            },
+                                            "baselineOffset": "NONE",
+                                            "smallCaps": false,
+                                            "strikethrough": false,
+                                            "underline": false,
+                                            "weightedFontFamily": {
+                                                "fontFamily": "Arial",
+                                                "weight": 400
+                                            }
+                                        }
+                                    },
+                                    "4": {
+                                        "bulletStyle": {
+                                            "backgroundColor": {},
+                                            "foregroundColor": {
+                                                "opaqueColor": {
+                                                    "rgbColor": {}
+                                                }
+                                            },
+                                            "bold": false,
+                                            "italic": false,
+                                            "fontFamily": "Arial",
+                                            "fontSize": {
+                                                "magnitude": 11,
+                                                "unit": "PT"
+                                            },
+                                            "baselineOffset": "NONE",
+                                            "smallCaps": false,
+                                            "strikethrough": false,
+                                            "underline": false,
+                                            "weightedFontFamily": {
+                                                "fontFamily": "Arial",
+                                                "weight": 400
+                                            }
+                                        }
+                                    },
+                                    "5": {
+                                        "bulletStyle": {
+                                            "backgroundColor": {},
+                                            "foregroundColor": {
+                                                "opaqueColor": {
+                                                    "rgbColor": {}
+                                                }
+                                            },
+                                            "bold": false,
+                                            "italic": false,
+                                            "fontFamily": "Arial",
+                                            "fontSize": {
+                                                "magnitude": 11,
+                                                "unit": "PT"
+                                            },
+                                            "baselineOffset": "NONE",
+                                            "smallCaps": false,
+                                            "strikethrough": false,
+                                            "underline": false,
+                                            "weightedFontFamily": {
+                                                "fontFamily": "Arial",
+                                                "weight": 400
+                                            }
+                                        }
+                                    },
+                                    "6": {
+                                        "bulletStyle": {
+                                            "backgroundColor": {},
+                                            "foregroundColor": {
+                                                "opaqueColor": {
+                                                    "rgbColor": {}
+                                                }
+                                            },
+                                            "bold": false,
+                                            "italic": false,
+                                            "fontFamily": "Arial",
+                                            "fontSize": {
+                                                "magnitude": 11,
+                                                "unit": "PT"
+                                            },
+                                            "baselineOffset": "NONE",
+                                            "smallCaps": false,
+                                            "strikethrough": false,
+                                            "underline": false,
+                                            "weightedFontFamily": {
+                                                "fontFamily": "Arial",
+                                                "weight": 400
+                                            }
+                                        }
+                                    },
+                                    "7": {
+                                        "bulletStyle": {
+                                            "backgroundColor": {},
+                                            "foregroundColor": {
+                                                "opaqueColor": {
+                                                    "rgbColor": {}
+                                                }
+                                            },
+                                            "bold": false,
+                                            "italic": false,
+                                            "fontFamily": "Arial",
+                                            "fontSize": {
+                                                "magnitude": 11,
+                                                "unit": "PT"
+                                            },
+                                            "baselineOffset": "NONE",
+                                            "smallCaps": false,
+                                            "strikethrough": false,
+                                            "underline": false,
+                                            "weightedFontFamily": {
+                                                "fontFamily": "Arial",
+                                                "weight": 400
+                                            }
+                                        }
+                                    },
+                                    "8": {
+                                        "bulletStyle": {
+                                            "backgroundColor": {},
+                                            "foregroundColor": {
+                                                "opaqueColor": {
+                                                    "rgbColor": {}
+                                                }
+                                            },
+                                            "bold": false,
+                                            "italic": false,
+                                            "fontFamily": "Arial",
+                                            "fontSize": {
+                                                "magnitude": 11,
+                                                "unit": "PT"
+                                            },
+                                            "baselineOffset": "NONE",
+                                            "smallCaps": false,
+                                            "strikethrough": false,
+                                            "underline": false,
+                                            "weightedFontFamily": {
+                                                "fontFamily": "Arial",
+                                                "weight": 400
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    },
+                    "shapeProperties": {
+                        "shapeBackgroundFill": {
+                            "propertyState": "NOT_RENDERED",
+                            "solidFill": {
+                                "color": {
+                                    "rgbColor": {
+                                        "red": 1,
+                                        "green": 1,
+                                        "blue": 1
+                                    }
+                                },
+                                "alpha": 1
+                            }
+                        },
+                        "outline": {
+                            "outlineFill": {
+                                "solidFill": {
+                                    "color": {
+                                        "rgbColor": {}
+                                    },
+                                    "alpha": 1
+                                }
+                            },
+                            "weight": {
+                                "magnitude": 9525,
+                                "unit": "EMU"
+                            },
+                            "dashStyle": "SOLID",
+                            "propertyState": "NOT_RENDERED"
+                        },
+                        "shadow": {
+                            "type": "OUTER",
+                            "transform": {
+                                "scaleX": 1,
+                                "scaleY": 1,
+                                "unit": "EMU"
+                            },
+                            "alignment": "BOTTOM_LEFT",
+                            "blurRadius": {
+                                "unit": "EMU"
+                            },
+                            "color": {
+                                "rgbColor": {}
+                            },
+                            "alpha": 1,
+                            "rotateWithShape": false,
+                            "propertyState": "NOT_RENDERED"
+                        },
+                        "contentAlignment": "TOP"
+                    },
+                    "placeholder": {
+                        "type": "BODY",
+                        "index": 1
+                    }
+                }
+            }
+        ],
+        "pageProperties": {
+            "pageBackgroundFill": {
+                "propertyState": "NOT_RENDERED",
+                "solidFill": {
+                    "color": {
+                        "rgbColor": {
+                            "red": 1,
+                            "green": 1,
+                            "blue": 1
+                        }
+                    },
+                    "alpha": 1
+                }
+            },
+            "colorScheme": {
+                "colors": [
+                    {
+                        "type": "DARK1",
+                        "color": {}
+                    },
+                    {
+                        "type": "LIGHT1",
+                        "color": {
+                            "red": 1,
+                            "green": 1,
+                            "blue": 1
+                        }
+                    },
+                    {
+                        "type": "DARK2",
+                        "color": {
+                            "red": 0.08235294,
+                            "green": 0.5058824,
+                            "blue": 0.34509805
+                        }
+                    },
+                    {
+                        "type": "LIGHT2",
+                        "color": {
+                            "red": 0.9529412,
+                            "green": 0.9529412,
+                            "blue": 0.9529412
+                        }
+                    },
+                    {
+                        "type": "ACCENT1",
+                        "color": {
+                            "red": 0.019607844,
+                            "green": 0.5529412,
+                            "blue": 0.78039217
+                        }
+                    },
+                    {
+                        "type": "ACCENT2",
+                        "color": {
+                            "red": 0.3137255,
+                            "green": 0.7058824,
+                            "blue": 0.19607843
+                        }
+                    },
+                    {
+                        "type": "ACCENT3",
+                        "color": {
+                            "red": 0.92941177,
+                            "green": 0.3372549,
+                            "blue": 0.105882354
+                        }
+                    },
+                    {
+                        "type": "ACCENT4",
+                        "color": {
+                            "red": 0.92941177,
+                            "green": 0.9372549
+                        }
+                    },
+                    {
+                        "type": "ACCENT5",
+                        "color": {
+                            "red": 0.14117648,
+                            "green": 0.79607844,
+                            "blue": 0.8980392
+                        }
+                    },
+                    {
+                        "type": "ACCENT6",
+                        "color": {
+                            "red": 0.39215687,
+                            "green": 0.8980392,
+                            "blue": 0.44705883
+                        }
+                    },
+                    {
+                        "type": "HYPERLINK",
+                        "color": {
+                            "red": 0.13333334,
+                            "blue": 0.8
+                        }
+                    },
+                    {
+                        "type": "FOLLOWED_HYPERLINK",
+                        "color": {
+                            "red": 0.33333334,
+                            "green": 0.101960786,
+                            "blue": 0.54509807
+                        }
+                    },
+                    {
+                        "type": "TEXT1",
+                        "color": {}
+                    },
+                    {
+                        "type": "BACKGROUND1",
+                        "color": {
+                            "red": 1,
+                            "green": 1,
+                            "blue": 1
+                        }
+                    },
+                    {
+                        "type": "TEXT2",
+                        "color": {
+                            "red": 0.9529412,
+                            "green": 0.9529412,
+                            "blue": 0.9529412
+                        }
+                    },
+                    {
+                        "type": "BACKGROUND2",
+                        "color": {
+                            "red": 0.08235294,
+                            "green": 0.5058824,
+                            "blue": 0.34509805
+                        }
+                    }
+                ]
+            }
+        }
+    }
+}
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2


From 6927418364d58c2aaba1b25f1d11537dd510535c Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Thu, 22 Aug 2019 08:29:43 -0400
Subject: fixed autoheight for text

---
 src/client/views/nodes/FormattedTextBox.tsx | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

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

diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 3f3360eff..849f942b6 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -735,12 +735,10 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
 
     @action
     tryUpdateHeight() {
-        if (this.props.Document.autoHeight && this._ref.current!.scrollHeight !== 0) {
-            let xf = this._ref.current!.getBoundingClientRect();
-            let scrBounds = this.props.ScreenToLocalTransform().transformBounds(0, 0, xf.width, this._ref.current!.textContent === "" ? 35 : this._ref.current!.scrollHeight);
+        let sh = this._ref.current ? this._ref.current.scrollHeight : 0;
+        if (this.props.Document.autoHeight && sh !== 0) {
             let nh = this.props.Document.isTemplate ? 0 : NumCast(this.dataDoc.nativeHeight, 0);
             let dh = NumCast(this.props.Document.height, 0);
-            let sh = scrBounds.height;
             const ChromeHeight = MainOverlayTextBox.Instance.ChromeHeight;
             this.props.Document.height = Math.max(10, (nh ? dh / nh * sh : sh) + (ChromeHeight ? ChromeHeight() : 0));
             this.dataDoc.nativeHeight = nh ? sh : undefined;
-- 
cgit v1.2.3-70-g09d2


From 8cffe031fe364e19897cfb638cffa9e4056c4343 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Thu, 22 Aug 2019 11:07:11 -0400
Subject: fixed textheight with titles. fixed marquee with floating docs. other
 tweaks.

---
 src/client/util/DocumentManager.ts                   |  4 +++-
 src/client/views/MainOverlayTextBox.tsx              |  1 +
 .../views/collections/CollectionStackingView.tsx     | 13 ++++++++-----
 .../views/collections/CollectionViewChromes.tsx      | 14 +++++++++-----
 .../collections/collectionFreeForm/MarqueeView.tsx   | 20 ++++++++++++++++++--
 src/client/views/nodes/DocumentView.tsx              | 10 ++++++++--
 src/client/views/nodes/FormattedTextBox.tsx          |  6 ++++--
 7 files changed, 51 insertions(+), 17 deletions(-)

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

diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index 7f526b247..124faf266 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -9,6 +9,7 @@ import { CollectionView } from '../views/collections/CollectionView';
 import { DocumentView } from '../views/nodes/DocumentView';
 import { LinkManager } from './LinkManager';
 import { undoBatch, UndoManager } from './UndoManager';
+import { Scripting } from './Scripting';
 
 
 export class DocumentManager {
@@ -202,4 +203,5 @@ export class DocumentManager {
             return 1;
         }
     }
-}
\ No newline at end of file
+}
+Scripting.addGlobal(function focus(doc: any) { DocumentManager.Instance.getDocumentViews(Doc.GetProto(doc)).map(view => view.props.focus(doc, true)) })
\ No newline at end of file
diff --git a/src/client/views/MainOverlayTextBox.tsx b/src/client/views/MainOverlayTextBox.tsx
index 9fe435bc5..0839e1114 100644
--- a/src/client/views/MainOverlayTextBox.tsx
+++ b/src/client/views/MainOverlayTextBox.tsx
@@ -144,6 +144,7 @@ export class MainOverlayTextBox extends React.Component<MainOverlayTextBoxProps>
                                 Document={FormattedTextBox.InputBoxOverlay.props.Document}
                                 DataDoc={FormattedTextBox.InputBoxOverlay.props.DataDoc}
                                 onClick={undefined}
+                                ChromeHeight={this.ChromeHeight}
                                 isSelected={returnTrue} select={emptyFunction} renderDepth={0} selectOnLoad={true}
                                 ContainingCollectionView={undefined} whenActiveChanged={emptyFunction} active={returnTrue} ContentScaling={returnOne}
                                 ScreenToLocalTransform={this._textXf} PanelWidth={returnZero} PanelHeight={returnZero} focus={emptyFunction}
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index be6ee1756..4ab656744 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -287,15 +287,18 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
     masonryChildren(docs: Doc[]) {
         this._docXfs.length = 0;
         return docs.map((d, i) => {
+            const pair = Doc.GetLayoutDataDocPair(this.props.Document, this.props.DataDoc, this.props.fieldKey, d);
+            if (!pair.layout || pair.data instanceof Promise) {
+                return (null);
+            }
             let dref = React.createRef<HTMLDivElement>();
-            let layoutDoc = Doc.expandTemplateLayout(d, this.props.DataDoc);
             let width = () => (d.nativeWidth && !d.ignoreAspect && !this.props.Document.fillColumn ? Math.min(d[WidthSym](), this.columnWidth) : this.columnWidth);/// (uniqueHeadings.length + 1);
-            let height = () => this.getDocHeight(layoutDoc);
-            let dxf = () => this.getDocTransform(layoutDoc!, dref.current!);
+            let height = () => this.getDocHeight(pair.layout);
+            let dxf = () => this.getDocTransform(pair.layout!, dref.current!);
             let rowSpan = Math.ceil((height() + this.gridGap) / this.gridGap);
             this._docXfs.push({ dxf: dxf, width: width, height: height });
-            return !layoutDoc ? (null) : <div className="collectionStackingView-masonryDoc" key={d[Id]} ref={dref} style={{ gridRowEnd: `span ${rowSpan}` }} >
-                {this.getDisplayDoc(layoutDoc, d, dxf, width)}
+            return !pair.layout ? (null) : <div className="collectionStackingView-masonryDoc" key={d[Id]} ref={dref} style={{ gridRowEnd: `span ${rowSpan}` }} >
+                {this.getDisplayDoc(pair.layout, pair.data, dxf, width)}
             </div>;
         });
     }
diff --git a/src/client/views/collections/CollectionViewChromes.tsx b/src/client/views/collections/CollectionViewChromes.tsx
index 25b152d4e..74e57611d 100644
--- a/src/client/views/collections/CollectionViewChromes.tsx
+++ b/src/client/views/collections/CollectionViewChromes.tsx
@@ -297,11 +297,15 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro
 
     datePickerRef = (node: HTMLInputElement) => {
         if (node) {
-            this._picker = datepicker("#" + node.id, {
-                disabler: (date: Date) => date > new Date(),
-                onSelect: (instance: any, date: Date) => runInAction(() => this._dateValue = date),
-                dateSelected: new Date()
-            });
+            try {
+                this._picker = datepicker("#" + node.id, {
+                    disabler: (date: Date) => date > new Date(),
+                    onSelect: (instance: any, date: Date) => runInAction(() => this._dateValue = date),
+                    dateSelected: new Date()
+                });
+            } catch (e) {
+                console.log("date picker exception:" + e);
+            }
         }
     }
     render() {
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index aad26efa0..221237365 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -373,7 +373,7 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
     marqueeSelect(selectBackgrounds: boolean = true) {
         let selRect = this.Bounds;
         let selection: Doc[] = [];
-        this.props.activeDocuments().filter(doc => !doc.isBackground).map(doc => {
+        this.props.activeDocuments().filter(doc => !doc.isBackground && doc.z === undefined).map(doc => {
             var x = NumCast(doc.x);
             var y = NumCast(doc.y);
             var w = NumCast(doc.width);
@@ -383,7 +383,7 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
             }
         });
         if (!selection.length && selectBackgrounds) {
-            this.props.activeDocuments().map(doc => {
+            this.props.activeDocuments().filter(doc => doc.z === undefined).map(doc => {
                 var x = NumCast(doc.x);
                 var y = NumCast(doc.y);
                 var w = NumCast(doc.width);
@@ -393,6 +393,22 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
                 }
             });
         }
+        if (!selection.length) {
+            let left = this._downX < this._lastX ? this._downX : this._lastX;
+            let top = this._downY < this._lastY ? this._downY : this._lastY;
+            let topLeft = this.props.getContainerTransform().transformPoint(left, top);
+            let size = this.props.getContainerTransform().transformDirection(this._lastX - this._downX, this._lastY - this._downY);
+            let otherBounds = { left: topLeft[0], top: topLeft[1], width: Math.abs(size[0]), height: Math.abs(size[1]) };
+            this.props.activeDocuments().filter(doc => doc.z !== undefined).map(doc => {
+                var x = NumCast(doc.x);
+                var y = NumCast(doc.y);
+                var w = NumCast(doc.width);
+                var h = NumCast(doc.height);
+                if (this.intersectRect({ left: x, top: y, width: w, height: h }, otherBounds)) {
+                    selection.push(doc);
+                }
+            });
+        }
         return selection;
     }
 
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 8dadf2bef..0c577af86 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -715,7 +715,13 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     chromeHeight = () => {
         let showOverlays = this.props.showOverlays ? this.props.showOverlays(this.layoutDoc) : undefined;
         let showTitle = showOverlays && "title" in showOverlays ? showOverlays.title : StrCast(this.layoutDoc.showTitle);
-        return showTitle ? 25 : 0;
+        let templates = Cast(this.layoutDoc.templates, listSpec("string"));
+        if (!showOverlays && templates instanceof List) {
+            templates.map(str => {
+                if (!showTitle && str.indexOf("{props.Document.title}") !== -1) showTitle = "title";
+            });
+        }
+        return (showTitle ? 25 : 0) + 1;// bcz: why 8??
     }
 
     get layoutDoc() {
@@ -769,7 +775,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                 {!showTitle && !showCaption ? this.contents :
                     <div style={{ position: "absolute", display: "inline-block", width: "100%", height: "100%", pointerEvents: "none" }}>
 
-                        <div style={{ width: "100%", height: showTextTitle ? "calc(100% - 33px)" : "100%", display: "inline-block", position: "absolute", top: showTextTitle ? "29px" : undefined }}>
+                        <div style={{ width: "100%", height: showTextTitle ? "calc(100% - 29px)" : "100%", display: "inline-block", position: "absolute", top: showTextTitle ? "29px" : undefined }}>
                             {this.contents}
                         </div>
                         {!showTitle ? (null) :
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 849f942b6..94d9f2f66 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -374,6 +374,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
                 this.unhighlightSearchTerms();
             }
         }, { fireImmediately: true });
+        this.tryUpdateHeight();
     }
 
     pushToGoogleDoc = async () => {
@@ -735,11 +736,12 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
 
     @action
     tryUpdateHeight() {
+        const ChromeHeight = this.props.ChromeHeight;
         let sh = this._ref.current ? this._ref.current.scrollHeight : 0;
+        console.log(this.props.Document.title + " " + sh + " " + (ChromeHeight && ChromeHeight()));
         if (this.props.Document.autoHeight && sh !== 0) {
             let nh = this.props.Document.isTemplate ? 0 : NumCast(this.dataDoc.nativeHeight, 0);
             let dh = NumCast(this.props.Document.height, 0);
-            const ChromeHeight = MainOverlayTextBox.Instance.ChromeHeight;
             this.props.Document.height = Math.max(10, (nh ? dh / nh * sh : sh) + (ChromeHeight ? ChromeHeight() : 0));
             this.dataDoc.nativeHeight = nh ? sh : undefined;
         }
@@ -775,7 +777,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
             <div className={`formattedTextBox-cont-${style}`} ref={this._ref}
                 style={{
                     overflowY: this.props.Document.autoHeight ? "hidden" : "auto",
-                    height: this.props.height ? this.props.height : undefined,
+                    height: this.props.Document.autoHeight ? "max-content" : this.props.height ? this.props.height : undefined,
                     background: this.props.hideOnLeave ? "rgba(0,0,0 ,0.4)" : undefined,
                     opacity: this.props.hideOnLeave ? (this._entered || this.props.isSelected() || Doc.IsBrushed(this.props.Document) ? 1 : 0.1) : 1,
                     color: this.props.color ? this.props.color : this.props.hideOnLeave ? "white" : "inherit",
-- 
cgit v1.2.3-70-g09d2


From 7812945012c320743a4271787ad614b2011c74a3 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Thu, 22 Aug 2019 11:18:19 -0400
Subject: from last

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

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

diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 94d9f2f66..1cc3e821f 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -374,7 +374,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
                 this.unhighlightSearchTerms();
             }
         }, { fireImmediately: true });
-        this.tryUpdateHeight();
+        setTimeout(() => this.tryUpdateHeight(), 0);
     }
 
     pushToGoogleDoc = async () => {
-- 
cgit v1.2.3-70-g09d2


From 0ee435f6bd686c667a067fa750b4589cedfb0070 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Thu, 22 Aug 2019 11:18:41 -0400
Subject: again

---
 src/client/views/nodes/FormattedTextBox.tsx | 1 -
 1 file changed, 1 deletion(-)

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

diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 1cc3e821f..44a481953 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -738,7 +738,6 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
     tryUpdateHeight() {
         const ChromeHeight = this.props.ChromeHeight;
         let sh = this._ref.current ? this._ref.current.scrollHeight : 0;
-        console.log(this.props.Document.title + " " + sh + " " + (ChromeHeight && ChromeHeight()));
         if (this.props.Document.autoHeight && sh !== 0) {
             let nh = this.props.Document.isTemplate ? 0 : NumCast(this.dataDoc.nativeHeight, 0);
             let dh = NumCast(this.props.Document.height, 0);
-- 
cgit v1.2.3-70-g09d2


From 65aec7b22e63de15e0d911971fa4e5a32d09d9b5 Mon Sep 17 00:00:00 2001
From: Sam Wilkins <samwilkins333@gmail.com>
Date: Thu, 22 Aug 2019 12:00:47 -0400
Subject: cleanup

---
 src/client/util/DictationManager.ts         | 30 ++++++++++++++++++-----------
 src/client/views/GlobalKeyHandler.ts        |  2 +-
 src/client/views/MainView.tsx               |  1 -
 src/client/views/nodes/FormattedTextBox.tsx |  2 +-
 src/new_fields/RichTextField.ts             |  6 ++++++
 5 files changed, 27 insertions(+), 14 deletions(-)

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

diff --git a/src/client/util/DictationManager.ts b/src/client/util/DictationManager.ts
index 781e5e465..fb3c15cea 100644
--- a/src/client/util/DictationManager.ts
+++ b/src/client/util/DictationManager.ts
@@ -64,6 +64,7 @@ export namespace DictationManager {
         export type ListeningUIStatus = { interim: boolean } | false;
 
         export interface ListeningOptions {
+            useOverlay: boolean;
             language: string;
             continuous: ContinuityArgs;
             delimiters: DelimiterArgs;
@@ -74,27 +75,34 @@ export namespace DictationManager {
 
         export const listen = async (options?: Partial<ListeningOptions>) => {
             let results: string | undefined;
-            // let main = MainView.Instance;
+            let main = MainView.Instance;
 
-            // main.dictationOverlayVisible = true;
-            // main.isListening = { interim: false };
+            let overlay = options !== undefined && options.useOverlay;
+            if (overlay) {
+                main.dictationOverlayVisible = true;
+                main.isListening = { interim: false };
+            }
 
             try {
                 results = await listenImpl(options);
                 if (results) {
                     Utils.CopyText(results);
-                    // main.isListening = false;
-                    // let execute = options && options.tryExecute;
-                    // main.dictatedPhrase = execute ? results.toLowerCase() : results;
-                    // main.dictationSuccess = execute ? await DictationManager.Commands.execute(results) : true;
+                    if (overlay) {
+                        main.isListening = false;
+                        let execute = options && options.tryExecute;
+                        main.dictatedPhrase = execute ? results.toLowerCase() : results;
+                        main.dictationSuccess = execute ? await DictationManager.Commands.execute(results) : true;
+                    }
                     options && options.tryExecute && await DictationManager.Commands.execute(results);
                 }
             } catch (e) {
-                // main.isListening = false;
-                // main.dictatedPhrase = results = `dictation error: ${"error" in e ? e.error : "unknown error"}`;
-                // main.dictationSuccess = false;
+                if (overlay) {
+                    main.isListening = false;
+                    main.dictatedPhrase = results = `dictation error: ${"error" in e ? e.error : "unknown error"}`;
+                    main.dictationSuccess = false;
+                }
             } finally {
-                // main.initiateDictationFade();
+                overlay && main.initiateDictationFade();
             }
 
             return results;
diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts
index 8a7295c65..d0464bd5f 100644
--- a/src/client/views/GlobalKeyHandler.ts
+++ b/src/client/views/GlobalKeyHandler.ts
@@ -105,7 +105,7 @@ export default class KeyManager {
 
         switch (keyname) {
             case " ":
-                DictationManager.Controls.listen({ tryExecute: true });
+                DictationManager.Controls.listen({ useOverlay: true, tryExecute: true });
                 stopPropagation = true;
                 preventDefault = true;
         }
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 0286a201b..f28844009 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -40,7 +40,6 @@ import { PreviewCursor } from './PreviewCursor';
 import { FilterBox } from './search/FilterBox';
 import PresModeMenu from './presentationview/PresentationModeMenu';
 import { PresBox } from './nodes/PresBox';
-import { GoogleApiClientUtils } from '../apis/google_docs/GoogleApiClientUtils';
 
 @observer
 export class MainView extends React.Component {
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index d9043c739..5492a457d 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -1,6 +1,6 @@
 import { library } from '@fortawesome/fontawesome-svg-core';
 import { faEdit, faSmile, faTextHeight, faUpload } from '@fortawesome/free-solid-svg-icons';
-import { action, computed, IReactionDisposer, Lambda, observable, reaction, runInAction, autorun } from "mobx";
+import { action, computed, IReactionDisposer, Lambda, observable, reaction, runInAction } from "mobx";
 import { observer } from "mobx-react";
 import { baseKeymap } from "prosemirror-commands";
 import { history } from "prosemirror-history";
diff --git a/src/new_fields/RichTextField.ts b/src/new_fields/RichTextField.ts
index cae5623e6..1b52e6f82 100644
--- a/src/new_fields/RichTextField.ts
+++ b/src/new_fields/RichTextField.ts
@@ -28,6 +28,12 @@ export class RichTextField extends ObjectField {
         return `new RichTextField("${this.Data}")`;
     }
 
+    public static Initialize = (initial: string) => {
+        !initial.length && (initial = " ");
+        let pos = initial.length + 1;
+        return `{"doc":{"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"${initial}"}]}]},"selection":{"type":"text","anchor":${pos},"head":${pos}}}`;
+    }
+
     [ToPlainText]() {
         // Because we're working with plain text, just concatenate all paragraphs
         let content = JSON.parse(this.Data).doc.content;
-- 
cgit v1.2.3-70-g09d2


From f0f0cc36654183921076db5a341fe7cac2bfdd3c Mon Sep 17 00:00:00 2001
From: monikahedman <monika_hedman@brown.edu>
Date: Thu, 22 Aug 2019 12:08:12 -0400
Subject: cleaned up

---
 src/client/views/collections/collectionFreeForm/MarqueeView.tsx | 1 -
 src/client/views/nodes/FormattedTextBox.tsx                     | 9 +--------
 2 files changed, 1 insertion(+), 9 deletions(-)

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

diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index e70d526c5..27eafd769 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -203,7 +203,6 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
     onClick = (e: React.MouseEvent): void => {
         if (Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD &&
             Math.abs(e.clientY - this._downY) < Utils.DRAG_THRESHOLD) {
-            //this is probably the wrong transform
             PreviewCursor.Show(e.clientX, e.clientY, this.onKeyPress, this.props.addLiveTextDocument, this.props.getTransform, this.props.addDocument);
             // let the DocumentView stopPropagation of this event when it selects this document
         } else {  // why do we get a click event when the cursor have moved a big distance?
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 0c0ab4d87..1db66d4a0 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -145,7 +145,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
 
 
     paste = (e: ClipboardEvent) => {
-        //this is throwing a ton of erros so i had to comment it out
+        //this is throwing a ton of errors so commented it out
         if (e.clipboardData && this._editorView) {
             // let pdfPasteText = `${Utils.GenerateDeterministicGuid("pdf paste")}`;
             // for (let i = 0; i < e.clipboardData.items.length; i++) {
@@ -173,13 +173,6 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
         }
     }
 
-    public setText = (text: string) => {
-        const tx = this._editorView!.state.tr.insertText(text);
-        const state = this._editorView!.state;
-        this._editorView!.dispatch(tx);
-        return new RichTextField(JSON.stringify(state.toJSON()));
-    }
-
     dispatchTransaction = (tx: Transaction) => {
         if (this._editorView) {
             const state = this._editorView.state.apply(tx);
-- 
cgit v1.2.3-70-g09d2


From e680f97f9d50ce5759d4533bae38af341956ddce Mon Sep 17 00:00:00 2001
From: Sam Wilkins <samwilkins333@gmail.com>
Date: Fri, 23 Aug 2019 11:26:43 -0400
Subject: cleanup

---
 src/client/views/nodes/FormattedTextBox.tsx | 5 -----
 src/server/index.ts                         | 2 +-
 2 files changed, 1 insertion(+), 6 deletions(-)

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

diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 191a24664..0e04bacf7 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -34,16 +34,12 @@ import "./FormattedTextBox.scss";
 import React = require("react");
 import { GoogleApiClientUtils, Pulls, Pushes } from '../../apis/google_docs/GoogleApiClientUtils';
 import { DocumentDecorations } from '../DocumentDecorations';
-import { MainOverlayTextBox } from '../MainOverlayTextBox';
 import { DictationManager } from '../../util/DictationManager';
 import { ReplaceStep } from 'prosemirror-transform';
 
 library.add(faEdit);
 library.add(faSmile, faTextHeight, faUpload);
 
-// FormattedTextBox: Displays an editable plain text node that maps to a specified Key of a Document
-//
-
 export const Blank = `{"doc":{"type":"doc","content":[]},"selection":{"type":"text","anchor":0,"head":0}}`;
 
 export interface FormattedTextBoxProps {
@@ -146,7 +142,6 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
 
 
     paste = (e: ClipboardEvent) => {
-        //this is throwing a ton of errors so commented it out
         if (e.clipboardData && this._editorView) {
             // let pdfPasteText = `${Utils.GenerateDeterministicGuid("pdf paste")}`;
             // for (let i = 0; i < e.clipboardData.items.length; i++) {
diff --git a/src/server/index.ts b/src/server/index.ts
index eeadef239..34a0a19f1 100644
--- a/src/server/index.ts
+++ b/src/server/index.ts
@@ -447,7 +447,7 @@ function LoadPage(file: string, pageNumber: number, res: Response) {
             console.log(pageNumber);
             pdf.getPage(pageNumber).then((page: Pdfjs.PDFPageProxy) => {
                 console.log("reading " + page);
-                let viewport = page.getViewport(1 as any);
+                let viewport = page.getViewport(1);
                 let canvasAndContext = factory.create(viewport.width, viewport.height);
                 let renderContext = {
                     canvasContext: canvasAndContext.context,
-- 
cgit v1.2.3-70-g09d2


From 538187907421057212eca1eadbe07c8b79705d1d Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Fri, 23 Aug 2019 16:47:49 -0400
Subject: fixed text scrolling issues.

---
 src/client/views/DocumentDecorations.tsx    | 2 +-
 src/client/views/MainOverlayTextBox.tsx     | 5 +++--
 src/client/views/nodes/FormattedTextBox.tsx | 2 +-
 3 files changed, 5 insertions(+), 4 deletions(-)

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

diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index a28088032..2c5940467 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -695,7 +695,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
         if (!canPush) return (null);
         let published = Doc.GetProto(this.targetDoc)[GoogleRef] !== undefined;
         if (!published) {
-            this.targetDoc.autoHeight = true;
+            // this.targetDoc.autoHeight = true;
         }
         let icon: IconProp = published ? (this.pushIcon as any) : cloud;
         return (
diff --git a/src/client/views/MainOverlayTextBox.tsx b/src/client/views/MainOverlayTextBox.tsx
index 0839e1114..e95e5b777 100644
--- a/src/client/views/MainOverlayTextBox.tsx
+++ b/src/client/views/MainOverlayTextBox.tsx
@@ -59,7 +59,7 @@ export class MainOverlayTextBox extends React.Component<MainOverlayTextBoxProps>
                         let sxf = Utils.GetScreenTransform(box ? box.CurrentDiv : undefined);
                         return new Transform(-sxf.translateX, -sxf.translateY, 1 / sxf.scale);
                     };
-                    this.setTextDoc(box.props.fieldKey, box.CurrentDiv, xf, BoolCast(box.props.Document.autoHeight, false) || box.props.height === "min-content");
+                    this.setTextDoc(box.props.fieldKey, box.CurrentDiv, xf, BoolCast(box.props.Document.autoHeight) || box.props.height === "min-content");
                 }
                 else {
                     this.TextDoc = undefined;
@@ -131,10 +131,11 @@ export class MainOverlayTextBox extends React.Component<MainOverlayTextBoxProps>
         this.TextDoc; this.TextDataDoc;
         if (FormattedTextBox.InputBoxOverlay && this._textTargetDiv) {
             let wid = FormattedTextBox.InputBoxOverlay.props.Document.width; // need to force overlay to render when underlying text box is resized (eg, w/ DocDecorations)
+            let hgtx = FormattedTextBox.InputBoxOverlay.props.Document.height; // need to force overlay to render when underlying text box is resized (eg, w/ DocDecorations)
             let textRect = this._textTargetDiv.getBoundingClientRect();
             let s = this._textXf().Scale;
             let location = this._textBottom ? textRect.bottom : textRect.top;
-            let hgt = this._textAutoHeight || this._textBottom ? "auto" : this._textTargetDiv.clientHeight;
+            let hgt = (this._textBox && this._textBox.props.Document.autoHeight) || this._textBottom ? "auto" : this._textTargetDiv.clientHeight;
             return <div ref={this._setouterdiv} className="mainOverlayTextBox-unscaled_div" style={{ transform: `translate(${textRect.left}px, ${location}px)` }} >
                 <div className="mainOverlayTextBox-textInput" style={{ transform: `scale(${1 / s})`, width: "auto", height: "0px" }} >
                     <div className="mainOverlayTextBox-textInput" onPointerDown={this.textBoxDown} ref={this._textProxyDiv} onScroll={this.textScroll}
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 0e04bacf7..91596e825 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -796,7 +796,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
     tryUpdateHeight() {
         const ChromeHeight = this.props.ChromeHeight;
         let sh = this._ref.current ? this._ref.current.scrollHeight : 0;
-        if (this.props.Document.autoHeight && sh !== 0) {
+        if (!this.props.isOverlay && this.props.Document.autoHeight && sh !== 0) {
             let nh = this.props.Document.isTemplate ? 0 : NumCast(this.dataDoc.nativeHeight, 0);
             let dh = NumCast(this.props.Document.height, 0);
             this.props.Document.height = Math.max(10, (nh ? dh / nh * sh : sh) + (ChromeHeight ? ChromeHeight() : 0));
-- 
cgit v1.2.3-70-g09d2


From 9fb7008b5cce6fd8973ec48cf6b067f3c4cfd363 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Fri, 23 Aug 2019 17:41:11 -0400
Subject: fixed documents disappearing without an x/y, fixed dropping something
 onto textbox making it a template, fixed treeview to show minimized
 documents.

---
 src/client/views/DocumentDecorations.tsx                       |  2 +-
 src/client/views/collections/CollectionTreeView.tsx            |  1 +
 .../collections/collectionFreeForm/CollectionFreeFormView.tsx  |  2 +-
 src/client/views/nodes/FormattedTextBox.tsx                    | 10 ++++++----
 4 files changed, 9 insertions(+), 6 deletions(-)

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

diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 2c5940467..ee2a57bd3 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -1,7 +1,7 @@
 import { library, IconProp } from '@fortawesome/fontawesome-svg-core';
 import { faLink, faTag, faTimes, faArrowAltCircleDown, faArrowAltCircleUp, faCheckCircle, faStopCircle, faCloudUploadAlt, faSyncAlt, faShare } from '@fortawesome/free-solid-svg-icons';
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { action, computed, observable, reaction, runInAction } from "mobx";
+import { action, computed, observable, reaction, runInAction, trace } from "mobx";
 import { observer } from "mobx-react";
 import { Doc } from "../../new_fields/Doc";
 import { List } from "../../new_fields/List";
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 7e1aacd5d..6e284a76f 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -373,6 +373,7 @@ class TreeView extends React.Component<TreeViewProps> {
         return <>
             <div className="docContainer" id={`docContainer-${this.props.parentKey}`} ref={reference} onPointerDown={onItemDown}
                 style={{
+                    color: this.props.document.isMinimized ? "red" : "black",
                     background: Doc.IsBrushed(this.props.document) ? "#06121212" : "0",
                     outline: BoolCast(this.props.document.workspaceBrush) ? "dashed 1px #06123232" : undefined,
                     pointerEvents: this.props.active() || SelectionManager.GetIsDragging() ? "all" : "none"
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 0a2dcbe3b..f185222ce 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -760,7 +760,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
                             ele: <CollectionFreeFormDocumentView key={doc[Id]}
                                 x={script ? pos.x : undefined} y={script ? pos.y : undefined}
                                 width={script ? pos.width : undefined} height={script ? pos.height : undefined} {...this.getChildDocumentViewProps(pair.layout, pair.data)} />,
-                            bounds: (pos.x !== undefined && pos.y !== undefined) ? { x: pos.x, y: pos.y, z: pos.z, width: NumCast(pos.width), height: NumCast(pos.height) } : undefined
+                            bounds: { x: pos.x || 0, y: pos.y || 0, z: pos.z, width: NumCast(pos.width), height: NumCast(pos.height) }
                         });
                     }
                 }
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 91596e825..876d4c428 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -36,6 +36,7 @@ import { GoogleApiClientUtils, Pulls, Pushes } from '../../apis/google_docs/Goog
 import { DocumentDecorations } from '../DocumentDecorations';
 import { DictationManager } from '../../util/DictationManager';
 import { ReplaceStep } from 'prosemirror-transform';
+import { DocumentType } from '../../documents/DocumentTypes';
 
 library.add(faEdit);
 library.add(faSmile, faTextHeight, faUpload);
@@ -256,10 +257,11 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
             let model: NodeType = (url.includes(".mov") || url.includes(".mp4")) ? schema.nodes.video : schema.nodes.image;
             this._editorView!.dispatch(this._editorView!.state.tr.insert(0, model.create({ src: url })));
             e.stopPropagation();
-        } else {
-            if (de.data instanceof DragManager.DocumentDragData) {
-                this.props.Document.layout = de.data.draggedDocuments[0];
-                de.data.draggedDocuments[0].isTemplate = true;
+        } else if (de.data instanceof DragManager.DocumentDragData) {
+            const draggedDoc = de.data.draggedDocuments.length && de.data.draggedDocuments[0];
+            if (draggedDoc && draggedDoc.type === DocumentType.TEXT && StrCast(draggedDoc.layout) != "") {
+                this.props.Document.layout = draggedDoc;
+                draggedDoc.isTemplate = true;
                 e.stopPropagation();
             }
         }
-- 
cgit v1.2.3-70-g09d2


From d237c67b236ce66e9bc711931e4c283a8c1e95f2 Mon Sep 17 00:00:00 2001
From: Sam Wilkins <samwilkins333@gmail.com>
Date: Fri, 23 Aug 2019 18:46:35 -0400
Subject: linter

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

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

diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 876d4c428..d6ba1700a 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -259,7 +259,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
             e.stopPropagation();
         } else if (de.data instanceof DragManager.DocumentDragData) {
             const draggedDoc = de.data.draggedDocuments.length && de.data.draggedDocuments[0];
-            if (draggedDoc && draggedDoc.type === DocumentType.TEXT && StrCast(draggedDoc.layout) != "") {
+            if (draggedDoc && draggedDoc.type === DocumentType.TEXT && StrCast(draggedDoc.layout) !== "") {
                 this.props.Document.layout = draggedDoc;
                 draggedDoc.isTemplate = true;
                 e.stopPropagation();
-- 
cgit v1.2.3-70-g09d2


From 094bbd52f2b55f501357a9f6b057042ad7684f27 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Mon, 26 Aug 2019 16:58:24 -0400
Subject: playing more with bulleted lists.

---
 src/client/util/ProsemirrorExampleTransfer.ts | 70 +++++++++++++++++++++------
 src/client/util/RichTextRules.ts              |  3 +-
 src/client/util/RichTextSchema.tsx            | 10 +++-
 src/client/util/TooltipTextMenu.tsx           | 10 +++-
 src/client/views/nodes/FormattedTextBox.tsx   | 12 ++---
 5 files changed, 78 insertions(+), 27 deletions(-)

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

diff --git a/src/client/util/ProsemirrorExampleTransfer.ts b/src/client/util/ProsemirrorExampleTransfer.ts
index b928532d6..3cdfba59a 100644
--- a/src/client/util/ProsemirrorExampleTransfer.ts
+++ b/src/client/util/ProsemirrorExampleTransfer.ts
@@ -2,8 +2,8 @@ import { chainCommands, exitCode, joinDown, joinUp, lift, selectParentNode, setB
 import { redo, undo } from "prosemirror-history";
 import { undoInputRule } from "prosemirror-inputrules";
 import { Schema } from "prosemirror-model";
-import { liftListItem, splitListItem, wrapInList } from "prosemirror-schema-list";
-import { EditorState, Transaction } from "prosemirror-state";
+import { liftListItem, splitListItem, wrapInList, sinkListItem } from "prosemirror-schema-list";
+import { EditorState, Transaction, TextSelection, NodeSelection } from "prosemirror-state";
 import { TooltipTextMenu } from "./TooltipTextMenu";
 
 const mac = typeof navigator !== "undefined" ? /Mac/.test(navigator.platform) : false;
@@ -79,32 +79,72 @@ export default function buildKeymap<S extends Schema<any>>(schema: S, mapKeys?:
 
     bind("Mod-s", TooltipTextMenu.insertStar);
 
-    bind("Shift-Tab", (state: EditorState<S>, dispatch: (tx: Transaction<S>) => void) => {
-        var marks = state.storedMarks || (state.selection.$to.parentOffset && state.selection.$from.marks());
-        liftListItem(schema.nodes.list_item)(state, (tx2: Transaction) => {
-            marks && tx2.ensureMarks(marks);
-            marks && tx2.setStoredMarks(marks);
-            dispatch(tx2);
-        });
-    });
 
+    let levelMark = (depth: number) => {
+        let p10 = schema.marks.pFontSize.create({ fontSize: 10 });
+        let p14 = schema.marks.pFontSize.create({ fontSize: 14 });
+        let p18 = schema.marks.pFontSize.create({ fontSize: 18 });
+        let p24 = schema.marks.pFontSize.create({ fontSize: 24 });
+        return depth == 0 ? p24 : depth == 2 ? p18 : depth == 4 ? p14 : p10;
+    }
     let bulletFunc = (state: EditorState<S>, dispatch: (tx: Transaction<S>) => void) => {
         var ref = state.selection;
         var range = ref.$from.blockRange(ref.$to);
         var marks = state.storedMarks || (state.selection.$to.parentOffset && state.selection.$from.marks());
         let depth = range && range.depth ? range.depth : 0;
         let nodeType = depth == 2 ? schema.nodes.cap_alphabet_list : depth == 4 ? schema.nodes.roman_list : depth == 6 ? schema.nodes.alphabet_list : schema.nodes.ordered_list;
+        let nodeTypeMark = depth == 2 ? schema.marks.mcap_alphabet_list : depth == 4 ? schema.marks.mroman_list : depth == 6 ? schema.marks.malphabet_list : schema.marks.mordered_list;
+        let created = levelMark(depth);
+        if (!sinkListItem(nodeType /*schema.nodes.list_item */)(state, (tx2: Transaction) => {
+            const resolvedPos = tx2.doc.resolve(range!.start);
+
+            let ns = new NodeSelection(resolvedPos);
+            let tx3 = tx2.addMark(ns.from - 1, ns.to, created).addMark(ns.from - 1, ns.to, nodeTypeMark as any).setSelection(TextSelection.create(tx2.doc, ns.to - (depth == 0 ? 3 : 1)));
+            marks && tx3.ensureMarks([...marks, created]);
+            marks && tx3.setStoredMarks([...marks, created]);
 
-        if (!wrapInList(nodeType)(state, (tx2: Transaction) => {
-            marks && tx2.ensureMarks(marks);
-            marks && tx2.setStoredMarks(marks);
-            dispatch(tx2);
+            dispatch(tx3);
         })) {
-            console.log("bullet fail");
+            let sxf = state.tr.setSelection(TextSelection.create(state.doc, range!.start, range!.end));
+            let newstate = state.applyTransaction(sxf);
+            if (!wrapInList(nodeType)(newstate.state, (tx2: Transaction) => {
+                const resolvedPos = tx2.doc.resolve(range!.start);
+                let ns = new TextSelection(resolvedPos, tx2.doc.resolve(range!.end + 1)); // new NodeSelection(resolvedPos);
+                let tx3 = tx2.setSelection(ns).removeMark(ns.from, ns.to, created).addMark(ns.from, ns.to, created).setSelection(TextSelection.create(tx2.doc, ns.to));
+                let tx4 = depth > 0 ? tx3.insertText(" ").setSelection(TextSelection.create(tx2.doc, ns.to - 2, ns.to + 2)).deleteSelection() : tx3;
+                marks && tx4.ensureMarks([...marks, created]);
+                marks && tx4.setStoredMarks([...marks, created]);
+
+                dispatch(tx4);
+            })) {
+                console.log("bullet fail");
+            }
         }
     }
     bind("Tab", (state: EditorState<S>, dispatch: (tx: Transaction<S>) => void) => bulletFunc(state, dispatch));
 
+    bind("Shift-Tab", (state: EditorState<S>, dispatch: (tx: Transaction<S>) => void) => {
+        var ref = state.selection;
+        var range = ref.$from.blockRange(ref.$to);
+        var marks = state.storedMarks || (state.selection.$to.parentOffset && state.selection.$from.marks());
+        let created = levelMark(range && range.depth ? range.depth - 4 : 0);
+        liftListItem(schema.nodes.list_item)(state, (tx2: Transaction) => {
+            try {
+                const resolvedPos = tx2.doc.resolve(Math.round((range!.start + range!.end) / 2));
+                let nodeIndex = resolvedPos.pos - (resolvedPos.nodeBefore && resolvedPos.nodeBefore.type.name === "text" ? resolvedPos.nodeBefore!.nodeSize : 0);
+                let ns = new NodeSelection(tx2.doc.resolve(nodeIndex));
+                if (resolvedPos.nodeAfter && resolvedPos.nodeAfter.type.name === "list_item")
+                    ns = new NodeSelection(tx2.doc.resolve(nodeIndex + 1));
+                let tx3 = tx2.setSelection(ns).removeMark(ns.from, ns.to, created).addMark(ns.from, ns.to, created).setSelection(TextSelection.create(tx2.doc, ns.to));
+                marks && tx3.ensureMarks([...marks, created]);
+                marks && tx3.setStoredMarks([...marks, created]);
+                dispatch(tx3);
+            } catch (e) {
+                dispatch(tx2);
+            }
+        });
+    });
+
     bind("Enter", (state: EditorState<S>, dispatch: (tx: Transaction<S>) => void) => {
         var marks = state.storedMarks || (state.selection.$to.parentOffset && state.selection.$from.marks());
         if (!splitListItem(schema.nodes.list_item)(state, (tx3: Transaction) => {
diff --git a/src/client/util/RichTextRules.ts b/src/client/util/RichTextRules.ts
index 89933650b..8c4c76027 100644
--- a/src/client/util/RichTextRules.ts
+++ b/src/client/util/RichTextRules.ts
@@ -26,7 +26,7 @@ export const inpRules = {
             match => ({ order: +match[1] }),
             (match, node) => node.childCount + node.attrs.order === +match[1]
         ),
-        // 1. ordered list
+        // a. alphabbetical list
         wrappingInputRule(
             /^([a-z]+)\.\s$/,
             schema.nodes.alphabet_list,
@@ -34,7 +34,6 @@ export const inpRules = {
             (match, node) => node.childCount + node.attrs.order === +match[1]
         ),
 
-
         // * bullet list
         wrappingInputRule(/^\s*([-+*])\s$/, schema.nodes.bullet_list),
 
diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx
index a8ce4731c..f128162c2 100644
--- a/src/client/util/RichTextSchema.tsx
+++ b/src/client/util/RichTextSchema.tsx
@@ -319,6 +319,15 @@ export const marks: { [index: string]: MarkSpec } = {
         toDOM: () => ['sup']
     },
 
+    malphabet_list: {
+    },
+    mcap_alphabet_list: {
+    },
+    mroman_list: {
+    },
+    mo_list: {
+    },
+
     highlight: {
         parseDOM: [{ style: 'color: blue' }],
         toDOM() {
@@ -412,7 +421,6 @@ export const marks: { [index: string]: MarkSpec } = {
         attrs: {
             fontSize: { default: 10 }
         },
-        inclusive: false,
         parseDOM: [{ style: 'font-size: 10px;' }],
         toDOM: (node) => ['span', {
             style: `font-size: ${node.attrs.fontSize}px;`
diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx
index 7a0c6f8c5..77396c829 100644
--- a/src/client/util/TooltipTextMenu.tsx
+++ b/src/client/util/TooltipTextMenu.tsx
@@ -165,7 +165,15 @@ export class TooltipTextMenu {
         this.fontSizeToNum.set(schema.marks.p48, 48);
         this.fontSizeToNum.set(schema.marks.p72, 72);
         this.fontSizeToNum.set(schema.marks.pFontSize, 10);
-        this.fontSizeToNum.set(schema.marks.pFontSize, 10);
+        // this.fontSizeToNum.set(schema.marks.pFontSize, 12);
+        // this.fontSizeToNum.set(schema.marks.pFontSize, 14);
+        // this.fontSizeToNum.set(schema.marks.pFontSize, 16);
+        // this.fontSizeToNum.set(schema.marks.pFontSize, 18);
+        // this.fontSizeToNum.set(schema.marks.pFontSize, 20);
+        // this.fontSizeToNum.set(schema.marks.pFontSize, 24);
+        // this.fontSizeToNum.set(schema.marks.pFontSize, 32);
+        // this.fontSizeToNum.set(schema.marks.pFontSize, 48);
+        // this.fontSizeToNum.set(schema.marks.pFontSize, 72);
         this.fontSizes = Array.from(this.fontSizeToNum.keys());
 
         //list types
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index d6ba1700a..acfd2a3b8 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -115,7 +115,6 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
 
     @undoBatch
     public setFontColor(color: string) {
-        let self = this;
         if (this._editorView!.state.selection.from === this._editorView!.state.selection.to) return false;
         if (this._editorView!.state.selection.to - this._editorView!.state.selection.from > this._editorView!.state.doc.nodeSize - 3) {
             this.props.Document.color = color;
@@ -176,15 +175,13 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
             FormattedTextBox._toolTipTextMenu && (FormattedTextBox._toolTipTextMenu.HackToFixTextSelectionGlitch = true);
             this._editorView.updateState(state);
             FormattedTextBox._toolTipTextMenu && (FormattedTextBox._toolTipTextMenu.HackToFixTextSelectionGlitch = false);
-            if (state.selection.empty && FormattedTextBox._toolTipTextMenu) {
-                const marks = tx.storedMarks;
-                if (marks) { FormattedTextBox._toolTipTextMenu.mark_key_pressed(marks); }
+            if (state.selection.empty && FormattedTextBox._toolTipTextMenu && tx.storedMarks) {
+                FormattedTextBox._toolTipTextMenu.mark_key_pressed(tx.storedMarks);
             }
 
             this._applyingChange = true;
-            const fieldkey = "preview";
-            if (this.extensionDoc) this.extensionDoc.text = state.doc.textBetween(0, state.doc.content.size, "\n\n");
-            if (this.extensionDoc) this.extensionDoc.lastModified = new DateField(new Date(Date.now()));
+            this.extensionDoc && (this.extensionDoc.text = state.doc.textBetween(0, state.doc.content.size, "\n\n"));
+            this.extensionDoc && (this.extensionDoc.lastModified = new DateField(new Date(Date.now())));
             this.dataDoc[this.props.fieldKey] = new RichTextField(JSON.stringify(state.toJSON()));
             this._applyingChange = false;
             let title = StrCast(this.dataDoc.title);
@@ -198,7 +195,6 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
 
     public highlightSearchTerms = (terms: String[]) => {
         if (this._editorView && (this._editorView as any).docView) {
-            const fieldkey = "preview";
             const doc = this._editorView.state.doc;
             const mark = this._editorView.state.schema.mark(this._editorView.state.schema.marks.search_highlight);
             doc.nodesBetween(0, doc.content.size, (node: ProsNode, pos: number, parent: ProsNode, index: number) => {
-- 
cgit v1.2.3-70-g09d2


From 34e0b1cf34474ec6765e212b6a35defefbfb49c9 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Tue, 27 Aug 2019 15:46:03 -0400
Subject: removed selectOnLoad prop.  fixed textboxes from deselecting on
 carriage return.

---
 src/client/views/MainOverlayTextBox.tsx                    |  2 +-
 src/client/views/MainView.tsx                              |  2 --
 src/client/views/OverlayView.tsx                           |  1 -
 src/client/views/collections/CollectionDockingView.tsx     |  1 -
 src/client/views/collections/CollectionSchemaCells.tsx     |  1 -
 src/client/views/collections/CollectionSchemaView.tsx      |  1 -
 .../collectionFreeForm/CollectionFreeFormView.tsx          | 14 +++-----------
 src/client/views/nodes/DocumentView.tsx                    |  4 +---
 src/client/views/nodes/FieldView.tsx                       |  2 --
 src/client/views/nodes/FormattedTextBox.tsx                |  9 ++++++---
 src/client/views/nodes/KeyValuePair.tsx                    |  1 -
 src/client/views/presentationview/PresentationElement.tsx  |  1 -
 src/client/views/search/SearchItem.tsx                     |  1 -
 13 files changed, 11 insertions(+), 29 deletions(-)

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

diff --git a/src/client/views/MainOverlayTextBox.tsx b/src/client/views/MainOverlayTextBox.tsx
index 65a291d99..f15b60347 100644
--- a/src/client/views/MainOverlayTextBox.tsx
+++ b/src/client/views/MainOverlayTextBox.tsx
@@ -156,7 +156,7 @@ export class MainOverlayTextBox extends React.Component<MainOverlayTextBoxProps>
                                 DataDoc={FormattedTextBox.InputBoxOverlay.props.DataDoc}
                                 onClick={undefined}
                                 ChromeHeight={this.ChromeHeight}
-                                isSelected={returnTrue} select={emptyFunction} renderDepth={0} selectOnLoad={true}
+                                isSelected={returnTrue} select={emptyFunction} renderDepth={0}
                                 ContainingCollectionView={undefined} whenActiveChanged={emptyFunction} active={returnTrue} ContentScaling={returnOne}
                                 ScreenToLocalTransform={this._textXf} PanelWidth={returnZero} PanelHeight={returnZero} focus={emptyFunction}
                                 pinToPres={returnZero} addDocTab={this.addDocTab} outer_div={(tooltip: HTMLElement) => { this._tooltip = tooltip; this.updateTooltip(); }} />
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index a02214deb..6b856443b 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -326,7 +326,6 @@ export class MainView extends React.Component {
                             PanelHeight={this.getPHeight}
                             renderDepth={0}
                             backgroundColor={returnEmptyString}
-                            selectOnLoad={false}
                             focus={emptyFunction}
                             parentActive={returnTrue}
                             whenActiveChanged={emptyFunction}
@@ -389,7 +388,6 @@ export class MainView extends React.Component {
             PanelWidth={this.flyoutWidthFunc}
             PanelHeight={this.getPHeight}
             renderDepth={0}
-            selectOnLoad={false}
             focus={emptyFunction}
             backgroundColor={returnEmptyString}
             parentActive={returnTrue}
diff --git a/src/client/views/OverlayView.tsx b/src/client/views/OverlayView.tsx
index a60dc591c..538614089 100644
--- a/src/client/views/OverlayView.tsx
+++ b/src/client/views/OverlayView.tsx
@@ -153,7 +153,6 @@ export class OverlayView extends React.Component {
                         PanelHeight={returnOne}
                         ScreenToLocalTransform={Transform.Identity}
                         renderDepth={1}
-                        selectOnLoad={false}
                         parentActive={returnTrue}
                         whenActiveChanged={emptyFunction}
                         focus={emptyFunction}
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index dc0cbda0b..95f94875c 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -636,7 +636,6 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
             PanelHeight={this.panelHeight}
             ScreenToLocalTransform={this.ScreenToLocalTransform}
             renderDepth={0}
-            selectOnLoad={false}
             parentActive={returnTrue}
             whenActiveChanged={emptyFunction}
             focus={emptyFunction}
diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx
index 551b485e7..9c26a08f0 100644
--- a/src/client/views/collections/CollectionSchemaCells.tsx
+++ b/src/client/views/collections/CollectionSchemaCells.tsx
@@ -153,7 +153,6 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
             isSelected: returnFalse,
             select: emptyFunction,
             renderDepth: this.props.renderDepth + 1,
-            selectOnLoad: false,
             ScreenToLocalTransform: Transform.Identity,
             focus: emptyFunction,
             active: returnFalse,
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index 4008dea51..9d83aa6c1 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -1006,7 +1006,6 @@ export class CollectionSchemaPreview extends React.Component<CollectionSchemaPre
                         parentActive={this.props.active}
                         ScreenToLocalTransform={this.getTransform}
                         renderDepth={this.props.renderDepth + 1}
-                        selectOnLoad={false}
                         ContentScaling={this.contentScaling}
                         PanelWidth={this.PanelWidth}
                         PanelHeight={this.PanelHeight}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index f185222ce..62f848a2b 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1,7 +1,7 @@
 import { library } from "@fortawesome/fontawesome-svg-core";
 import { faEye } from "@fortawesome/free-regular-svg-icons";
 import { faBraille, faChalkboard, faCompass, faCompressArrowsAlt, faExpandArrowsAlt, faPaintBrush, faTable, faUpload } from "@fortawesome/free-solid-svg-icons";
-import { action, computed, IReactionDisposer, observable, reaction } from "mobx";
+import { action, computed, IReactionDisposer, observable, reaction, trace } from "mobx";
 import { observer } from "mobx-react";
 import { Doc, DocListCastAsync, Field, FieldResult, HeightSym, Opt, WidthSym } from "../../../../new_fields/Doc";
 import { Id } from "../../../../new_fields/FieldSymbols";
@@ -38,6 +38,7 @@ import "./CollectionFreeFormView.scss";
 import { MarqueeView } from "./MarqueeView";
 import React = require("react");
 import { DocServer } from "../../../DocServer";
+import { FormattedTextBox } from "../../nodes/FormattedTextBox";
 
 library.add(faEye as any, faTable, faPaintBrush, faExpandArrowsAlt, faCompressArrowsAlt, faCompass, faUpload, faBraille, faChalkboard);
 
@@ -165,8 +166,6 @@ export namespace PivotView {
             return prev;
         }, elements);
 
-        target.resetSelectOnLoaded();
-
         return docViews;
     };
 
@@ -177,7 +176,6 @@ const PanZoomDocument = makeInterface(panZoomSchema, positionSchema, pageSchema)
 
 @observer
 export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
-    private _selectOnLoaded: string = ""; // id of document that should be selected once it's loaded (used for click-to-type)
     private _lastX: number = 0;
     private _lastY: number = 0;
     private get _pwidth() { return this.props.PanelWidth(); }
@@ -241,7 +239,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
     private getContainerTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-this.borderWidth, -this.borderWidth);
     private getLocalTransform = (): Transform => Transform.Identity().scale(1 / this.zoomScaling()).translate(this.panX(), this.panY());
     private addLiveTextBox = (newBox: Doc) => {
-        this._selectOnLoaded = newBox[Id];// track the new text box so we can give it a prop that tells it to focus itself when it's displayed
+        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
         this.addDocument(newBox, false);
     }
     private addDocument = (newBox: Doc, allowDuplicates: boolean) => {
@@ -642,7 +640,6 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
             onClick: this.props.onClick,
             ScreenToLocalTransform: childLayout.z ? this.getTransformOverlay : this.getTransform,
             renderDepth: this.props.renderDepth + 1,
-            selectOnLoad: childLayout[Id] === this._selectOnLoaded,
             PanelWidth: childLayout[WidthSym],
             PanelHeight: childLayout[HeightSym],
             ContentScaling: returnOne,
@@ -668,7 +665,6 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
             onClick: this.props.onClick,
             ScreenToLocalTransform: this.getTransform,
             renderDepth: this.props.renderDepth,
-            selectOnLoad: layoutDoc[Id] === this._selectOnLoaded,
             PanelWidth: layoutDoc[WidthSym],
             PanelHeight: layoutDoc[HeightSym],
             ContentScaling: returnOne,
@@ -768,13 +764,9 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
             return prev;
         }, elements);
 
-        this.resetSelectOnLoaded();
-
         return docviews;
     }
 
-    resetSelectOnLoaded = () => setTimeout(() => this._selectOnLoaded = "", 600);// bcz: surely there must be a better way ....
-
     @computed.struct
     get views() {
         let source = this.elements;
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 3cf86b6f9..f7ebfb75a 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -92,7 +92,6 @@ export interface DocumentViewProps {
     PanelWidth: () => number;
     PanelHeight: () => number;
     focus: (doc: Doc, willZoom: boolean, scale?: number) => void;
-    selectOnLoad: boolean;
     parentActive: () => boolean;
     whenActiveChanged: (isActive: boolean) => void;
     bringToFront: (doc: Doc, sendToBack?: boolean) => void;
@@ -717,7 +716,6 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
             isSelected={this.isSelected}
             select={this.select}
             onClick={this.onClickHandler}
-            selectOnLoad={this.props.selectOnLoad}
             layoutKey={"layout"}
             fitToBox={BoolCast(this.props.Document.fitToBox) ? true : this.props.fitToBox}
             DataDoc={this.dataDoc} />);
@@ -808,7 +806,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                         }
                         {!showCaption ? (null) :
                             <div style={{ position: "absolute", bottom: 0, transformOrigin: "bottom left", width: `${100 * this.props.ContentScaling()}%`, transform: `scale(${1 / this.props.ContentScaling()})` }}>
-                                <FormattedTextBox {...this.props} onClick={this.onClickHandler} DataDoc={this.dataDoc} active={returnTrue} isSelected={this.isSelected} focus={emptyFunction} select={this.select} selectOnLoad={this.props.selectOnLoad} fieldExt={""} hideOnLeave={true} fieldKey={showCaption} />
+                                <FormattedTextBox {...this.props} onClick={this.onClickHandler} DataDoc={this.dataDoc} active={returnTrue} isSelected={this.isSelected} focus={emptyFunction} select={this.select} fieldExt={""} hideOnLeave={true} fieldKey={showCaption} />
                             </div>
                         }
                     </div>
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index f0f1b3b73..d9774303b 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -36,7 +36,6 @@ export interface FieldViewProps {
     isSelected: () => boolean;
     select: (isCtrlPressed: boolean) => void;
     renderDepth: number;
-    selectOnLoad: boolean;
     addDocument?: (document: Doc, allowDuplicates?: boolean) => boolean;
     addDocTab: (document: Doc, dataDoc: Doc | undefined, where: string) => void;
     pinToPres: (document: Doc) => void;
@@ -108,7 +107,6 @@ export class FieldView extends React.Component<FieldViewProps> {
             //         PanelWidth={returnHundred}
             //         PanelHeight={returnHundred}
             //         renderDepth={0} //TODO Why is renderDepth reset?
-            //         selectOnLoad={false}
             //         focus={emptyFunction}
             //         isSelected={this.props.isSelected}
             //         select={returnFalse}
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index acfd2a3b8..c28bf1821 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -622,12 +622,15 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
             }
         }
 
-        if (this.props.selectOnLoad) {
-            if (!this.props.isOverlay) this.props.select(false);
-            else this._editorView!.focus();
+        if (this.props.Document[Id] == FormattedTextBox.SelectOnLoad) {
+            FormattedTextBox.SelectOnLoad = "";
+            this.props.select(false);
         }
+        else if (this.props.isOverlay) this._editorView!.focus();
     }
 
+    public static SelectOnLoad = "";
+
     componentWillUnmount() {
         this._editorView && this._editorView.destroy();
         this._reactionDisposer && this._reactionDisposer();
diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx
index 8001b24a7..5afd4d834 100644
--- a/src/client/views/nodes/KeyValuePair.tsx
+++ b/src/client/views/nodes/KeyValuePair.tsx
@@ -60,7 +60,6 @@ export class KeyValuePair extends React.Component<KeyValuePairProps> {
             isSelected: returnFalse,
             select: emptyFunction,
             renderDepth: 1,
-            selectOnLoad: false,
             active: returnFalse,
             whenActiveChanged: emptyFunction,
             ScreenToLocalTransform: Transform.Identity,
diff --git a/src/client/views/presentationview/PresentationElement.tsx b/src/client/views/presentationview/PresentationElement.tsx
index 83413814f..80aa25f48 100644
--- a/src/client/views/presentationview/PresentationElement.tsx
+++ b/src/client/views/presentationview/PresentationElement.tsx
@@ -359,7 +359,6 @@ export default class PresentationElement extends React.Component<PresentationEle
                     PanelHeight={() => 90}
                     focus={emptyFunction}
                     backgroundColor={returnEmptyString}
-                    selectOnLoad={false}
                     parentActive={returnFalse}
                     whenActiveChanged={returnFalse}
                     bringToFront={emptyFunction}
diff --git a/src/client/views/search/SearchItem.tsx b/src/client/views/search/SearchItem.tsx
index 41fc49c2e..672892fdf 100644
--- a/src/client/views/search/SearchItem.tsx
+++ b/src/client/views/search/SearchItem.tsx
@@ -209,7 +209,6 @@ export class SearchItem extends React.Component<SearchItemProps> {
                     PanelHeight={returnYDimension}
                     focus={emptyFunction}
                     backgroundColor={returnEmptyString}
-                    selectOnLoad={false}
                     parentActive={returnFalse}
                     whenActiveChanged={returnFalse}
                     bringToFront={emptyFunction}
-- 
cgit v1.2.3-70-g09d2


From 656a08a130124870c9f652f7b1529b2b496cdac7 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Tue, 27 Aug 2019 15:52:25 -0400
Subject: lint fixes.

---
 src/client/views/PreviewCursor.tsx                     | 2 +-
 src/client/views/collections/CollectionViewChromes.tsx | 2 ++
 src/client/views/nodes/DocumentView.tsx                | 2 +-
 src/client/views/nodes/FormattedTextBox.tsx            | 2 +-
 src/client/views/nodes/WebBox.tsx                      | 2 +-
 src/client/views/pdf/PDFViewer.tsx                     | 2 +-
 6 files changed, 7 insertions(+), 5 deletions(-)

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

diff --git a/src/client/views/PreviewCursor.tsx b/src/client/views/PreviewCursor.tsx
index d8e161ab6..1329dc02c 100644
--- a/src/client/views/PreviewCursor.tsx
+++ b/src/client/views/PreviewCursor.tsx
@@ -51,7 +51,7 @@ export class PreviewCursor extends React.Component<{}> {
                     // tests for URL and makes web document
                     let re: any = /^https?:\/\//g;
                     if (re.test(e.clipboardData.getData("text/plain"))) {
-                        const url = e.clipboardData.getData("text/plain")
+                        const url = e.clipboardData.getData("text/plain");
                         PreviewCursor._addDocument(Docs.Create.WebDocument(url, {
                             title: url, width: 300, height: 300,
                             // nativeWidth: 300, nativeHeight: 472.5,
diff --git a/src/client/views/collections/CollectionViewChromes.tsx b/src/client/views/collections/CollectionViewChromes.tsx
index b2df0e747..4b3f7c87e 100644
--- a/src/client/views/collections/CollectionViewChromes.tsx
+++ b/src/client/views/collections/CollectionViewChromes.tsx
@@ -42,11 +42,13 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro
 
     _templateCommand = {
         title: "set template", script: "this.target.childLayout = this.source ? this.source[0] : undefined", params: ["target", "source"],
+        initialize: emptyFunction,
         immediate: (draggedDocs: Doc[]) => this.props.CollectionView.props.Document.childLayout = draggedDocs.length ? draggedDocs[0] : undefined
     };
     _contentCommand = {
         // title: "set content", script: "getProto(this.target).data = aliasDocs(this.source.map(async p => await p));", params: ["target", "source"],  // bcz: doesn't look like we can do async stuff in scripting...
         title: "set content", script: "getProto(this.target).data = aliasDocs(this.source);", params: ["target", "source"],
+        initialize: emptyFunction,
         immediate: (draggedDocs: Doc[]) => Doc.GetProto(this.props.CollectionView.props.Document).data = new List<Doc>(draggedDocs.map((d: any) => Doc.MakeAlias(d)))
     };
     _viewCommand = {
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index f7ebfb75a..4d5307c88 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -600,7 +600,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                 this.makeBtnClicked();
             }, icon: "window-restore"
         });
-        makes.push({ description: this.props.Document.ignoreClick ? "Selectable" : "Unselectable", event: () => this.props.Document.ignoreClick = !this.props.Document.ignoreClick, icon: this.props.Document.ignoreClick ? "unlock" : "lock" })
+        makes.push({ description: this.props.Document.ignoreClick ? "Selectable" : "Unselectable", event: () => this.props.Document.ignoreClick = !this.props.Document.ignoreClick, icon: this.props.Document.ignoreClick ? "unlock" : "lock" });
         !existingMake && cm.addItem({ description: "Make...", subitems: makes, icon: "hand-point-right" });
         let existing = ContextMenu.Instance.findByDescription("Layout...");
         let layoutItems: ContextMenuProps[] = existing && "subitems" in existing ? existing.subitems : [];
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index c28bf1821..49189c5f3 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -622,7 +622,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
             }
         }
 
-        if (this.props.Document[Id] == FormattedTextBox.SelectOnLoad) {
+        if (this.props.Document[Id] === FormattedTextBox.SelectOnLoad) {
             FormattedTextBox.SelectOnLoad = "";
             this.props.select(false);
         }
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index f0140d04b..642f58daf 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -18,7 +18,7 @@ import { Docs } from "../../documents/Documents";
 import { faStickyNote } from "@fortawesome/free-solid-svg-icons";
 import { library } from "@fortawesome/fontawesome-svg-core";
 
-library.add(faStickyNote)
+library.add(faStickyNote);
 
 @observer
 export class WebBox extends React.Component<FieldViewProps> {
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index e3bfea237..e5917fefc 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -163,7 +163,7 @@ export class PDFViewer extends React.Component<IViewerProps> {
                         <div key={`${this.props.url}-placeholder-${i + 1}`} className="pdfviewer-placeholder"
                             style={{ width: this._pageSizes[i].width, height: this._pageSizes[i].height }}>
                             "PAGE IS LOADING... "
-                </div>)
+                </div>);
                     this.getPlaceholderPage(i);
                 }))));
             this.props.loaded(Math.max(...this._pageSizes.map(i => i.width)), this._pageSizes[0].height, this.props.pdf.numPages);
-- 
cgit v1.2.3-70-g09d2


From 5da0459ad76c614e455ea99798c940d4e93707bb Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Tue, 27 Aug 2019 17:29:58 -0400
Subject: multi-user marks.

---
 src/client/util/RichTextSchema.tsx          | 13 +++++++++++++
 src/client/views/nodes/FormattedTextBox.tsx | 11 ++++++++++-
 2 files changed, 23 insertions(+), 1 deletion(-)

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

diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx
index bbced3b77..76c45e6c1 100644
--- a/src/client/util/RichTextSchema.tsx
+++ b/src/client/util/RichTextSchema.tsx
@@ -1,6 +1,7 @@
 import { DOMOutputSpecArray, MarkSpec, Node, NodeSpec, Schema, Slice } from "prosemirror-model";
 import { bulletList, listItem, orderedList } from 'prosemirror-schema-list';
 import { TextSelection } from "prosemirror-state";
+import { Doc } from "../../new_fields/Doc";
 
 const pDOM: DOMOutputSpecArray = ["p", 0], blockquoteDOM: DOMOutputSpecArray = ["blockquote", 0], hrDOM: DOMOutputSpecArray = ["hr"],
     preDOM: DOMOutputSpecArray = ["pre", ["code", 0]], brDOM: DOMOutputSpecArray = ["br"], ulDOM: DOMOutputSpecArray = ["ul", 0];
@@ -324,6 +325,18 @@ export const marks: { [index: string]: MarkSpec } = {
         }
     },
 
+    // the id of the user who entered the text
+    user_mark: {
+        attrs: {
+            userid: { default: "" }
+        },
+        toDOM(node: any) {
+            return ['span', {
+                style: `background: ${node.attrs.userid.indexOf(Doc.CurrentUserEmail) === -1 ? "rgba(255, 255, 0, 0.267)" : undefined};`
+            }];
+        }
+    },
+
 
     // :: MarkSpec Code font mark. Represented as a `<code>` element.
     code: {
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 49189c5f3..667bac3be 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -5,7 +5,7 @@ import { observer } from "mobx-react";
 import { baseKeymap } from "prosemirror-commands";
 import { history } from "prosemirror-history";
 import { keymap } from "prosemirror-keymap";
-import { Fragment, Node, Node as ProsNode, NodeType, Slice } from "prosemirror-model";
+import { Fragment, Node, Node as ProsNode, NodeType, Slice, Mark } from "prosemirror-model";
 import { EditorState, Plugin, Transaction, TextSelection } from "prosemirror-state";
 import { EditorView } from "prosemirror-view";
 import { DateField } from '../../../new_fields/DateField';
@@ -37,6 +37,7 @@ import { DocumentDecorations } from '../DocumentDecorations';
 import { DictationManager } from '../../util/DictationManager';
 import { ReplaceStep } from 'prosemirror-transform';
 import { DocumentType } from '../../documents/DocumentTypes';
+import { CurrentUserUtils } from '../../../server/authentication/models/current_user_utils';
 
 library.add(faEdit);
 library.add(faSmile, faTextHeight, faUpload);
@@ -171,6 +172,10 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
 
     dispatchTransaction = (tx: Transaction) => {
         if (this._editorView) {
+            var markerss = tx.storedMarks || (tx.selection.$to.parentOffset && tx.selection.$from.marks());
+            let newMarks = [...(markerss ? markerss.filter(m => m.type !== schema.marks.user_mark) : []), schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail })];
+            tx.ensureMarks(newMarks);
+            tx.setStoredMarks(newMarks);
             const state = this._editorView.state.apply(tx);
             FormattedTextBox._toolTipTextMenu && (FormattedTextBox._toolTipTextMenu.HackToFixTextSelectionGlitch = true);
             this._editorView.updateState(state);
@@ -267,6 +272,10 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
         if (this.props.Document !== SelectionManager.SelectedDocuments()[0].props.Document) {
             return;
         }
+        var markerss = this._editorView!.state.storedMarks || (this._editorView!.state.selection.$to.parentOffset && this._editorView!.state.selection.$from.marks());
+        let newMarks = [...(markerss ? markerss.filter(m => m.type !== schema.marks.user_mark) : []), schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail })];
+        this._editorView!.state.storedMarks = newMarks;
+
         if (e.key === "R" && e.altKey) {
             e.stopPropagation();
             e.preventDefault();
-- 
cgit v1.2.3-70-g09d2


From a7515d1e80e32fcc19096c73335f624042b85d51 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Tue, 27 Aug 2019 21:20:52 -0400
Subject: added auto-reformatting after shift-tab.

---
 src/client/views/MainOverlayTextBox.tsx     |  10 +-
 src/client/views/nodes/FormattedTextBox.tsx | 144 +++++++++++++---------------
 2 files changed, 67 insertions(+), 87 deletions(-)

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

diff --git a/src/client/views/MainOverlayTextBox.tsx b/src/client/views/MainOverlayTextBox.tsx
index f15b60347..755e5de14 100644
--- a/src/client/views/MainOverlayTextBox.tsx
+++ b/src/client/views/MainOverlayTextBox.tsx
@@ -50,14 +50,8 @@ export class MainOverlayTextBox extends React.Component<MainOverlayTextBoxProps>
             (box?: FormattedTextBox) => {
                 const tb = this._textBox;
                 const container = tb && tb.props.ContainingCollectionView;
-                if (tb && container) { // this hacky section is needed to force the edited text box to completely recreate itself since things can get out synch -- specifically, the bullet label state which is computed when the dom elements are created
-                    var dl = DocListCast(container.props.Document[container.props.fieldKey]);
-                    let dli = dl.indexOf(tb.props.Document);
-                    if (dli !== -1) {
-                        let prev = dli > 0 ? dl[dli - 1] : undefined;
-                        tb.props.removeDocument && tb.props.removeDocument(tb.props.Document);
-                        setTimeout(() => Doc.AddDocToList(container.props.Document, container.props.fieldKey, tb.props.Document, prev, false, dli === 0), 0);
-                    }
+                if (tb && container) {
+                    tb.rebuildEditor();// this forces the edited text box to completely recreate itself to avoid get out of sync -- e.g., bullet labels are only computed when the dom elements are created
                 }
                 this._textBox = box;
                 if (box) {
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 667bac3be..5cbbc3b55 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -15,7 +15,7 @@ import { List } from '../../../new_fields/List';
 import { RichTextField, ToPlainText, FromPlainText } from "../../../new_fields/RichTextField";
 import { BoolCast, Cast, NumCast, StrCast, DateCast } from "../../../new_fields/Types";
 import { createSchema, makeInterface } from "../../../new_fields/Schema";
-import { Utils } from '../../../Utils';
+import { Utils, numberRange } from '../../../Utils';
 import { DocServer } from "../../DocServer";
 import { Docs, DocUtils } from '../../documents/Documents';
 import { DocumentManager } from '../../util/DocumentManager';
@@ -37,7 +37,7 @@ import { DocumentDecorations } from '../DocumentDecorations';
 import { DictationManager } from '../../util/DictationManager';
 import { ReplaceStep } from 'prosemirror-transform';
 import { DocumentType } from '../../documents/DocumentTypes';
-import { CurrentUserUtils } from '../../../server/authentication/models/current_user_utils';
+import { number } from 'prop-types';
 
 library.add(faEdit);
 library.add(faSmile, faTextHeight, faUpload);
@@ -69,25 +69,25 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
     public static LayoutString(fieldStr: string = "data") {
         return FieldView.LayoutString(FormattedTextBox, fieldStr);
     }
-    public static Instance: FormattedTextBox;
-    private _ref: React.RefObject<HTMLDivElement>;
+    private static _toolTipTextMenu: TooltipTextMenu | undefined = undefined;
+    private _ref: React.RefObject<HTMLDivElement> = React.createRef();
     private _proseRef?: HTMLDivElement;
     private _editorView: Opt<EditorView>;
-    private static _toolTipTextMenu: TooltipTextMenu | undefined = undefined;
     private _applyingChange: boolean = false;
     private _linkClicked = "";
+    private _undoTyping?: UndoManager.Batch;
     private _reactionDisposer: Opt<IReactionDisposer>;
     private _searchReactionDisposer?: Lambda;
     private _textReactionDisposer: Opt<IReactionDisposer>;
     private _heightReactionDisposer: Opt<IReactionDisposer>;
     private _proxyReactionDisposer: Opt<IReactionDisposer>;
-    private pullReactionDisposer: Opt<IReactionDisposer>;
-    private pushReactionDisposer: Opt<IReactionDisposer>;
+    private _pullReactionDisposer: Opt<IReactionDisposer>;
+    private _pushReactionDisposer: Opt<IReactionDisposer>;
     private dropDisposer?: DragManager.DragDropDisposer;
-    public get CurrentDiv(): HTMLDivElement { return this._ref.current!; }
-    @observable _entered = false;
 
+    @observable private _entered = false;
     @observable public static InputBoxOverlay?: FormattedTextBox = undefined;
+    public static SelectOnLoad = "";
     public static InputBoxOverlayScroll: number = 0;
     public static IsFragment(html: string) {
         return html.indexOf("data-pm-slice") !== -1;
@@ -128,15 +128,13 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
 
     constructor(props: FieldViewProps) {
         super(props);
-        FormattedTextBox.Instance = this;
-        this._ref = React.createRef();
         if (this.props.isOverlay) {
             DragManager.StartDragFunctions.push(() => FormattedTextBox.InputBoxOverlay = undefined);
         }
-
-        document.addEventListener("paste", this.paste);
     }
 
+    public get CurrentDiv(): HTMLDivElement { return this._ref.current!; }
+
     @computed get extensionDoc() { return Doc.resolvedFieldDataDoc(this.dataDoc, this.props.fieldKey, "dummy"); }
 
     @computed get dataDoc() { return this.props.DataDoc && (BoolCast(this.props.Document.isTemplate) || BoolCast(this.props.DataDoc.isTemplate) || this.props.DataDoc.layout === this.props.Document) ? this.props.DataDoc : Doc.GetProto(this.props.Document); }
@@ -172,10 +170,12 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
 
     dispatchTransaction = (tx: Transaction) => {
         if (this._editorView) {
-            var markerss = tx.storedMarks || (tx.selection.$to.parentOffset && tx.selection.$from.marks());
-            let newMarks = [...(markerss ? markerss.filter(m => m.type !== schema.marks.user_mark) : []), schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail })];
-            tx.ensureMarks(newMarks);
-            tx.setStoredMarks(newMarks);
+            // var markerss = tx.storedMarks || (tx.selection.$to.parentOffset && tx.selection.$from.marks());
+            // let newMarks = [...(markerss ? markerss.filter(m => m.type !== schema.marks.user_mark) : []), schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail })];
+            // if (!this._down) {  // if the pointer is down, we're likely doing a drag selection.  If setStoreMarks is called during
+            //     tx.ensureMarks(newMarks);  // this operation, then it is likely (but not guaranteed) that nothing will be selected due to strange prosemirror behavior.
+            //     tx.setStoredMarks(newMarks);
+            // }
             const state = this._editorView.state.apply(tx);
             FormattedTextBox._toolTipTextMenu && (FormattedTextBox._toolTipTextMenu.HackToFixTextSelectionGlitch = true);
             this._editorView.updateState(state);
@@ -240,12 +240,8 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
 
     protected createDropTarget = (ele: HTMLDivElement) => {
         this._proseRef = ele;
-        if (this.dropDisposer) {
-            this.dropDisposer();
-        }
-        if (ele) {
-            this.dropDisposer = DragManager.MakeDropTarget(ele, { handlers: { drop: this.drop.bind(this) } });
-        }
+        this.dropDisposer && this.dropDisposer();
+        ele && (this.dropDisposer = DragManager.MakeDropTarget(ele, { handlers: { drop: this.drop.bind(this) } }));
     }
 
     @undoBatch
@@ -269,17 +265,12 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
     }
 
     recordKeyHandler = (e: KeyboardEvent) => {
-        if (this.props.Document !== SelectionManager.SelectedDocuments()[0].props.Document) {
-            return;
-        }
-        var markerss = this._editorView!.state.storedMarks || (this._editorView!.state.selection.$to.parentOffset && this._editorView!.state.selection.$from.marks());
-        let newMarks = [...(markerss ? markerss.filter(m => m.type !== schema.marks.user_mark) : []), schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail })];
-        this._editorView!.state.storedMarks = newMarks;
-
-        if (e.key === "R" && e.altKey) {
-            e.stopPropagation();
-            e.preventDefault();
-            this.recordBullet();
+        if (this.props.Document === SelectionManager.SelectedDocuments()[0].props.Document) {
+            if (e.key === "R" && e.altKey) {
+                e.stopPropagation();
+                e.preventDefault();
+                this.recordBullet();
+            }
         }
     }
 
@@ -323,15 +314,11 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
     }
 
     private newListItems = (count: number) => {
-        let listItems: any[] = [];
-        for (let i = 0; i < count; i++) {
-            listItems.push(schema.nodes.list_item.create(undefined, schema.nodes.paragraph.create()));
-        }
-        return listItems;
+        return numberRange(count).map(x => schema.nodes.list_item.create(undefined, schema.nodes.paragraph.create()));
     }
 
-    componentDidMount() {
-        const config = {
+    @computed get config() {
+        return {
             schema,
             inpRules, //these currently don't do anything, but could eventually be helpful
             plugins: this.props.isOverlay ? [
@@ -350,7 +337,16 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
                     keymap(buildKeymap(schema)),
                     keymap(baseKeymap),
                 ]
-        };
+        }
+    };
+
+    @action
+    rebuildEditor() {
+        this.setupEditor(this.config, this.dataDoc, this.props.fieldKey);
+    }
+
+    componentDidMount() {
+        document.addEventListener("paste", this.paste);
 
         if (!this.props.isOverlay) {
             this._proxyReactionDisposer = reaction(() => this.props.isSelected(),
@@ -373,13 +369,13 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
             incomingValue => {
                 if (this._editorView && !this._applyingChange) {
                     let updatedState = JSON.parse(incomingValue);
-                    this._editorView.updateState(EditorState.fromJSON(config, updatedState));
+                    this._editorView.updateState(EditorState.fromJSON(this.config, updatedState));
                     this.tryUpdateHeight();
                 }
             }
         );
 
-        this.pullReactionDisposer = reaction(
+        this._pullReactionDisposer = reaction(
             () => this.props.Document[Pulls],
             () => {
                 if (!DocumentDecorations.hasPulledHack) {
@@ -390,7 +386,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
             }
         );
 
-        this.pushReactionDisposer = reaction(
+        this._pushReactionDisposer = reaction(
             () => this.props.Document[Pushes],
             () => {
                 if (!DocumentDecorations.hasPushedHack) {
@@ -415,7 +411,9 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
                     this.dataDoc.lastModified = undefined;
                 }
             }, { fireImmediately: true });
-        this.setupEditor(config, this.dataDoc, this.props.fieldKey);
+
+
+        this.setupEditor(this.config, this.dataDoc, this.props.fieldKey);
 
         this._searchReactionDisposer = reaction(() => {
             return StrCast(this.props.Document.search_string);
@@ -515,7 +513,6 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
         }
     }
 
-
     clipboardTextSerializer = (slice: Slice): string => {
         let text = "", separated = true;
         const from = 0, to = slice.content.size;
@@ -615,6 +612,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
             }
         }
         if (this._proseRef) {
+            this._editorView && this._editorView.destroy();
             this._editorView = new EditorView(this._proseRef, {
                 state: field && field.Data ? EditorState.fromJSON(config, JSON.parse(field.Data)) : EditorState.create(config),
                 dispatchTransaction: this.dispatchTransaction,
@@ -638,20 +636,20 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
         else if (this.props.isOverlay) this._editorView!.focus();
     }
 
-    public static SelectOnLoad = "";
-
     componentWillUnmount() {
-        this._editorView && this._editorView.destroy();
         this._reactionDisposer && this._reactionDisposer();
         this._proxyReactionDisposer && this._proxyReactionDisposer();
         this._textReactionDisposer && this._textReactionDisposer();
-        this.pushReactionDisposer && this.pushReactionDisposer();
-        this.pullReactionDisposer && this.pullReactionDisposer();
+        this._pushReactionDisposer && this._pushReactionDisposer();
+        this._pullReactionDisposer && this._pullReactionDisposer();
         this._heightReactionDisposer && this._heightReactionDisposer();
         this._searchReactionDisposer && this._searchReactionDisposer();
+        document.removeEventListener("paste", this.paste);
     }
 
+    _down = false;
     onPointerDown = (e: React.PointerEvent): void => {
+        this._down = true;
         if (this.props.onClick && e.button === 0) {
             e.preventDefault();
         }
@@ -712,10 +710,9 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
             e.preventDefault();
         }
     }
+
     onPointerUp = (e: React.PointerEvent): void => {
-        if (FormattedTextBox._toolTipTextMenu && FormattedTextBox._toolTipTextMenu.tooltip) {
-            //this._toolTipTextMenu.tooltip.style.opacity = "1";
-        }
+        this._down = false;
         if (e.buttons === 1 && this.props.isSelected() && !e.altKey) {
             e.stopPropagation();
         }
@@ -763,7 +760,6 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
                 return self._toolTipTextMenu = new TooltipTextMenu(_editorView, myprops);
             }
         });
-        //this.props.Document.tooltip = self._toolTipTextMenu;
     }
 
     tooltipLinkingMenuPlugin() {
@@ -781,13 +777,22 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
             this._undoTyping = undefined;
         }
     }
-    public _undoTyping?: UndoManager.Batch;
     onKeyPress = (e: React.KeyboardEvent) => {
         if (e.key === "Escape") {
             SelectionManager.DeselectAll();
         }
         e.stopPropagation();
-        if (e.key === "Tab") e.preventDefault();
+        if (e.key === "Tab") {
+            e.preventDefault();
+            setTimeout(() => { // force re-rendering of bullet numbers that may have had their bullet labels change.  (Our prosemirrior code re-"marks" the changed bullets, but nothing causes the Dom to be re-rendered which is where the nubering takes place)
+                SelectionManager.DeselectAll();
+                SelectionManager.SelectDoc(DocumentManager.Instance.getDocumentView(this.props.Document, this.props.ContainingCollectionView)!, false);
+            }, 0);
+        }
+        var markerss = this._editorView!.state.storedMarks || (this._editorView!.state.selection.$to.parentOffset && this._editorView!.state.selection.$from.marks());
+        let newMarks = [...(markerss ? markerss.filter(m => m.type !== schema.marks.user_mark) : []), schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail })];
+        this._editorView!.state.storedMarks = newMarks;
+
         // stop propagation doesn't seem to stop propagation of native keyboard events.
         // so we set a flag on the native event that marks that the event's been handled.
         (e.nativeEvent as any).DASHFormattedTextBoxHandled = true;
@@ -814,24 +819,6 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
         }
     }
 
-    @action
-    onPointerEnter = (e: React.PointerEvent) => {
-        this._entered = true;
-    }
-    @action
-    onPointerLeave = (e: React.PointerEvent) => {
-        this._entered = false;
-    }
-
-    specificContextMenu = (e: React.MouseEvent): void => {
-        // let subitems: ContextMenuProps[] = [];
-        // subitems.push({
-        //     description: BoolCast(this.props.Document.autoHeight) ? "Manual Height" : "Auto Height",
-        //     event: action(() => Doc.GetProto(this.props.Document).autoHeight = !BoolCast(this.props.Document.autoHeight)), icon: "expand-arrows-alt"
-        // });
-        // ContextMenu.Instance.addItem({ description: "Text Funcs...", subitems: subitems, icon: "text-height" });
-    }
-
 
     render() {
         let self = this;
@@ -854,14 +841,13 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
                 onKeyDown={this.onKeyPress}
                 onFocus={this.onFocused}
                 onClick={this.onClick}
-                onContextMenu={this.specificContextMenu}
                 onBlur={this.onBlur}
                 onPointerUp={this.onPointerUp}
                 onPointerDown={this.onPointerDown}
                 onMouseDown={this.onMouseDown}
                 onWheel={this.onPointerWheel}
-                onPointerEnter={this.onPointerEnter}
-                onPointerLeave={this.onPointerLeave}
+                onPointerEnter={action(() => this._entered = true)}
+                onPointerLeave={action(() => this._entered = false)}
             >
                 <div className={`formattedTextBox-inner${rounded}`} ref={this.createDropTarget} style={{ whiteSpace: "pre-wrap" }} />
             </div>
-- 
cgit v1.2.3-70-g09d2


From 41c79ceb4b52965f374db750d06a04a94ecc8212 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Tue, 27 Aug 2019 21:21:30 -0400
Subject: from last

---
 src/client/views/nodes/FormattedTextBox.tsx | 6 ------
 1 file changed, 6 deletions(-)

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

diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 5cbbc3b55..ba558a0b2 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -170,12 +170,6 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
 
     dispatchTransaction = (tx: Transaction) => {
         if (this._editorView) {
-            // var markerss = tx.storedMarks || (tx.selection.$to.parentOffset && tx.selection.$from.marks());
-            // let newMarks = [...(markerss ? markerss.filter(m => m.type !== schema.marks.user_mark) : []), schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail })];
-            // if (!this._down) {  // if the pointer is down, we're likely doing a drag selection.  If setStoreMarks is called during
-            //     tx.ensureMarks(newMarks);  // this operation, then it is likely (but not guaranteed) that nothing will be selected due to strange prosemirror behavior.
-            //     tx.setStoredMarks(newMarks);
-            // }
             const state = this._editorView.state.apply(tx);
             FormattedTextBox._toolTipTextMenu && (FormattedTextBox._toolTipTextMenu.HackToFixTextSelectionGlitch = true);
             this._editorView.updateState(state);
-- 
cgit v1.2.3-70-g09d2


From 1fbf7d7e10bb4dfa7e3a323ee0641d7bbf97b6a8 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Tue, 27 Aug 2019 23:24:18 -0400
Subject: fixed several lint errors, and minor issues with bullets

---
 src/client/util/DocumentManager.ts                 |  2 +-
 src/client/util/ProsemirrorExampleTransfer.ts      | 17 ++++-----
 src/client/util/RichTextSchema.tsx                 | 13 ++++---
 src/client/util/TooltipTextMenu.tsx                | 31 ++++++++++++----
 src/client/views/DocumentDecorations.tsx           |  2 +-
 .../views/collections/CollectionTreeView.tsx       | 42 +++++++++++-----------
 .../views/collections/CollectionViewChromes.tsx    |  2 +-
 src/client/views/nodes/FormattedTextBox.tsx        |  6 ++--
 8 files changed, 71 insertions(+), 44 deletions(-)

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

diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index 124faf266..ec731da84 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -204,4 +204,4 @@ export class DocumentManager {
         }
     }
 }
-Scripting.addGlobal(function focus(doc: any) { DocumentManager.Instance.getDocumentViews(Doc.GetProto(doc)).map(view => view.props.focus(doc, true)) })
\ No newline at end of file
+Scripting.addGlobal(function focus(doc: any) { DocumentManager.Instance.getDocumentViews(Doc.GetProto(doc)).map(view => view.props.focus(doc, true)); });
\ No newline at end of file
diff --git a/src/client/util/ProsemirrorExampleTransfer.ts b/src/client/util/ProsemirrorExampleTransfer.ts
index 8b6936748..12ad28199 100644
--- a/src/client/util/ProsemirrorExampleTransfer.ts
+++ b/src/client/util/ProsemirrorExampleTransfer.ts
@@ -79,8 +79,7 @@ export default function buildKeymap<S extends Schema<any>>(schema: S, mapKeys?:
 
     bind("Mod-s", TooltipTextMenu.insertStar);
 
-    // let nodeTypeMark = depth == 2 ? "upper-alpha" : depth == 4 ? "lower-roman" : depth == 6 ? "lower-alpha" : "decimal";
-    let nodeTypeMark = (depth: number) => { return depth == 2 ? "decimal2" : depth == 4 ? "decimal3" : depth == 6 ? "decimal4" : "decimal" }
+    let nodeTypeMark = (depth: number) => depth === 2 ? "indent2" : depth === 4 ? "indent3" : depth === 6 ? "indent4" : "indent1";
 
     let bulletFunc = (state: EditorState<S>, dispatch: (tx: Transaction<S>) => void) => {
         var ref = state.selection;
@@ -90,7 +89,7 @@ export default function buildKeymap<S extends Schema<any>>(schema: S, mapKeys?:
         if (!sinkListItem(schema.nodes.list_item)(state, (tx2: Transaction) => {
             const resolvedPos = tx2.doc.resolve(range!.start);
 
-            let path = (resolvedPos as any).path as any;
+            let path = (resolvedPos as any).path;
             for (let i = path.length - 1; i > 0; i--) {
                 if (path[i].type === schema.nodes.ordered_list) {
                     path[i].attrs.bulletStyle = nodeTypeMark(depth);
@@ -105,7 +104,7 @@ export default function buildKeymap<S extends Schema<any>>(schema: S, mapKeys?:
             let newstate = state.applyTransaction(sxf);
             if (!wrapInList(schema.nodes.ordered_list)(newstate.state, (tx2: Transaction) => {
                 const resolvedPos = tx2.doc.resolve(Math.round((range!.start + range!.end) / 2));
-                let path = (resolvedPos as any).path as any;
+                let path = (resolvedPos as any).path;
                 for (let i = path.length - 1; i > 0; i--) {
                     if (path[i].type === schema.nodes.ordered_list) {
                         path[i].attrs.bulletStyle = nodeTypeMark(depth);
@@ -120,8 +119,9 @@ export default function buildKeymap<S extends Schema<any>>(schema: S, mapKeys?:
                 console.log("bullet fail");
             }
         }
-    }
-    bind("Tab", (state: EditorState<S>, dispatch: (tx: Transaction<S>) => void) => bulletFunc(state, dispatch));
+    };
+
+    bind("Tab", bulletFunc);
 
     bind("Shift-Tab", (state: EditorState<S>, dispatch: (tx: Transaction<S>) => void) => {
         var ref = state.selection;
@@ -132,7 +132,7 @@ export default function buildKeymap<S extends Schema<any>>(schema: S, mapKeys?:
             try {
                 const resolvedPos = tx2.doc.resolve(Math.round((range!.start + range!.end) / 2));
 
-                let path = (resolvedPos as any).path as any;
+                let path = (resolvedPos as any).path;
                 for (let i = path.length - 1; i > 0; i--) {
                     if (path[i].type === schema.nodes.ordered_list) {
                         path[i].attrs.bulletStyle = nodeTypeMark(depth);
@@ -159,7 +159,8 @@ export default function buildKeymap<S extends Schema<any>>(schema: S, mapKeys?:
             if (!splitBlockKeepMarks(state, (tx3: Transaction) => {
                 marks && tx3.ensureMarks(marks);
                 marks && tx3.setStoredMarks(marks);
-                if (!liftListItem(schema.nodes.list_item)(state, (tx4: Transaction) => dispatch(tx4))) {
+                if (!liftListItem(schema.nodes.list_item)(state, dispatch as ((tx: Transaction<Schema<any, any>>) => void))
+                ) {
                     dispatch(tx3);
                 }
             })) {
diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx
index 76c45e6c1..4e18f410d 100644
--- a/src/client/util/RichTextSchema.tsx
+++ b/src/client/util/RichTextSchema.tsx
@@ -177,10 +177,15 @@ export const nodes: { [index: string]: NodeSpec } = {
         group: 'block',
         attrs: {
             bulletStyle: { default: "" },
+            mapStyle: { default: "decimal" }
         },
         toDOM(node: Node<any>) {
-            for (let i = 0; i < node.childCount; i++) node.child(i).attrs.className = node.attrs.bulletStyle;
-            return ['ol', { class: `${node.attrs.bulletStyle}-ol`, style: `list-style: none;` }, 0]
+            const bs = node.attrs.bulletStyle;
+            const decMap = bs === "indent1" ? "decimal" : bs === "indent2" ? "decimal2" : bs === "indent3" ? "decimal3" : bs === "indent4" ? "decimal4" : "";
+            const multiMap = bs === "indent1" ? "decimal" : bs === "indent2" ? "upper-alpha" : bs === "indent3" ? "lower-roman" : bs === "indent4" ? "lower-alpha" : "";
+            let map = node.attrs.mapStyle === "decimal" ? decMap : multiMap;
+            for (let i = 0; i < node.childCount; i++) node.child(i).attrs.className = map;
+            return ['ol', { class: `${map}-ol`, style: `list-style: none;` }, 0];
             //return ['ol', { class: `${node.attrs.bulletStyle}`, style: `list-style: ${node.attrs.bulletStyle};`, 0]
         }
     },
@@ -192,7 +197,7 @@ export const nodes: { [index: string]: NodeSpec } = {
         // parseDOM: [{ tag: "ul" }, { style: 'list-style-type=disc' }],
         toDOM(node: Node<any>) {
             for (let i = 0; i < node.childCount; i++) node.child(i).attrs.className = "";
-            return ['ul', 0]
+            return ['ul', 0];
         }
     },
 
@@ -302,7 +307,7 @@ export const marks: { [index: string]: MarkSpec } = {
         },
         toDOM(node: any) {
             return ['span', {
-                style: `background: ${node.attrs.bulletType == "decimal" ? "yellow" : node.attrs.bulletType === "upper-alpha" ? "blue" : "green"}`
+                style: `background: ${node.attrs.bulletType === "decimal" ? "yellow" : node.attrs.bulletType === "upper-alpha" ? "blue" : "green"}`
             }];
         }
     },
diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx
index 7f6ba3aac..e979e6cde 100644
--- a/src/client/util/TooltipTextMenu.tsx
+++ b/src/client/util/TooltipTextMenu.tsx
@@ -28,11 +28,11 @@ export class TooltipTextMenu {
     private view: EditorView;
     private fontStyles: MarkType[];
     private fontSizes: MarkType[];
-    private listTypes: NodeType[];
+    private listTypes: (NodeType | any)[];
     private editorProps: FieldViewProps & FormattedTextBoxProps;
     private fontSizeToNum: Map<MarkType, number>;
     private fontStylesToName: Map<MarkType, string>;
-    private listTypeToIcon: Map<NodeType, string>;
+    private listTypeToIcon: Map<NodeType | any, string>;
     //private link: HTMLAnchorElement;
     private wrapper: HTMLDivElement;
     private extras: HTMLDivElement;
@@ -179,7 +179,8 @@ export class TooltipTextMenu {
         //list types
         this.listTypeToIcon = new Map();
         this.listTypeToIcon.set(schema.nodes.bullet_list, ":");
-        this.listTypeToIcon.set(schema.nodes.ordered_list, "1)");
+        this.listTypeToIcon.set(schema.nodes.ordered_list.create({ mapStyle: "decimal" }), "1.1");
+        this.listTypeToIcon.set(schema.nodes.ordered_list.create({ mapStyle: "multi" }), "1.A");
         // this.listTypeToIcon.set(schema.nodes.bullet_list, "⬜");
         this.listTypes = Array.from(this.listTypeToIcon.keys());
 
@@ -512,10 +513,28 @@ export class TooltipTextMenu {
 
     //remove all node typeand apply the passed-in one to the selected text
     changeToNodeType(nodeType: NodeType | undefined, view: EditorView) {
-        //remove old
-        liftListItem(schema.nodes.list_item)(view.state, view.dispatch);
-        if (nodeType) { //add new
+        //remove oldif (nodeType) { //add new
+        if (nodeType === schema.nodes.bullet_list) {
             wrapInList(nodeType)(view.state, view.dispatch);
+        } else {
+            var ref = view.state.selection;
+            var range = ref.$from.blockRange(ref.$to);
+            var marks = view.state.storedMarks || (view.state.selection.$to.parentOffset && view.state.selection.$from.marks());
+            wrapInList(schema.nodes.ordered_list)(view.state, (tx2: any) => {
+                const resolvedPos = tx2.doc.resolve(Math.round((range!.start + range!.end) / 2));
+                let path = resolvedPos.path;
+                for (let i = path.length - 1; i > 0; i--) {
+                    if (path[i].type === schema.nodes.ordered_list) {
+                        path[i].attrs.bulletStyle = "indent1";
+                        path[i].attrs.mapStyle = (nodeType as any).attrs.mapStyle;
+                        break;
+                    }
+                }
+                marks && tx2.ensureMarks([...marks]);
+                marks && tx2.setStoredMarks([...marks]);
+
+                view.dispatch(tx2);
+            });
         }
     }
 
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index e93893586..203227241 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -201,7 +201,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
     }
 
     @observable _forceUpdate = 0;
-    _lastBox = { x: 0, y: 0, r: 0, b: 0 }
+    _lastBox = { x: 0, y: 0, r: 0, b: 0 };
     @computed
     get Bounds(): { x: number, y: number, b: number, r: number } {
         let x = this._forceUpdate;
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 04133fb5b..50f03005c 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -432,26 +432,28 @@ class TreeView extends React.Component<TreeViewProps> {
         }
 
         let ascending = Cast(containingCollection.sortAscending, "boolean", null);
-        if (ascending !== undefined) docs.sort(function (a, b): 1 | -1 {
-            let descA = ascending ? b : a;
-            let descB = ascending ? a : b;
-            let first = descA.title;
-            let second = descB.title;
-            // TODO find better way to sort how to sort..................
-            if (typeof first === 'number' && typeof second === 'number') {
-                return (first - second) > 0 ? 1 : -1;
-            }
-            if (typeof first === 'string' && typeof second === 'string') {
-                return first > second ? 1 : -1;
-            }
-            if (typeof first === 'boolean' && typeof second === 'boolean') {
-                // if (first === second) { // bugfixing?: otherwise, the list "flickers" because the list is resorted during every load
-                //     return Number(descA.x) > Number(descB.x) ? 1 : -1;
-                // }
-                return first > second ? 1 : -1;
-            }
-            return ascending ? 1 : -1;
-        });
+        if (ascending !== undefined) {
+            docs.sort(function (a, b): 1 | -1 {
+                let descA = ascending ? b : a;
+                let descB = ascending ? a : b;
+                let first = descA.title;
+                let second = descB.title;
+                // TODO find better way to sort how to sort..................
+                if (typeof first === 'number' && typeof second === 'number') {
+                    return (first - second) > 0 ? 1 : -1;
+                }
+                if (typeof first === 'string' && typeof second === 'string') {
+                    return first > second ? 1 : -1;
+                }
+                if (typeof first === 'boolean' && typeof second === 'boolean') {
+                    // if (first === second) { // bugfixing?: otherwise, the list "flickers" because the list is resorted during every load
+                    //     return Number(descA.x) > Number(descB.x) ? 1 : -1;
+                    // }
+                    return first > second ? 1 : -1;
+                }
+                return ascending ? 1 : -1;
+            });
+        }
 
         let rowWidth = () => panelWidth() - 20;
         return docs.map((child, i) => {
diff --git a/src/client/views/collections/CollectionViewChromes.tsx b/src/client/views/collections/CollectionViewChromes.tsx
index 4b3f7c87e..c897af17e 100644
--- a/src/client/views/collections/CollectionViewChromes.tsx
+++ b/src/client/views/collections/CollectionViewChromes.tsx
@@ -53,7 +53,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro
     };
     _viewCommand = {
         title: "restore view", script: "this.target.panX = this.restoredPanX; this.target.panY = this.restoredPanY; this.target.scale = this.restoredScale;", params: ["target"],
-        immediate: (draggedDocs: Doc[]) => { this.props.CollectionView.props.Document.panX = 0; this.props.CollectionView.props.Document.panY = 0; this.props.CollectionView.props.Document.scale = 1 },
+        immediate: (draggedDocs: Doc[]) => { this.props.CollectionView.props.Document.panX = 0; this.props.CollectionView.props.Document.panY = 0; this.props.CollectionView.props.Document.scale = 1; },
         initialize: (button: Doc) => { button.restoredPanX = this.props.CollectionView.props.Document.panX; button.restoredPanY = this.props.CollectionView.props.Document.panY; button.restoredScale = this.props.CollectionView.props.Document.scale; }
     };
     _freeform_commands = [this._contentCommand, this._templateCommand, this._viewCommand];
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index ba558a0b2..36740fc66 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -331,8 +331,8 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
                     keymap(buildKeymap(schema)),
                     keymap(baseKeymap),
                 ]
-        }
-    };
+        };
+    }
 
     @action
     rebuildEditor() {
@@ -776,7 +776,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
             SelectionManager.DeselectAll();
         }
         e.stopPropagation();
-        if (e.key === "Tab") {
+        if (e.key === "Tab" || e.key === "Enter") { // bullets typically change "levels" when tab or enter is used.  sometimes backspcae, so maybe that should be added.
             e.preventDefault();
             setTimeout(() => { // force re-rendering of bullet numbers that may have had their bullet labels change.  (Our prosemirrior code re-"marks" the changed bullets, but nothing causes the Dom to be re-rendered which is where the nubering takes place)
                 SelectionManager.DeselectAll();
-- 
cgit v1.2.3-70-g09d2


From be517c301997b617ba642d7f0745a254a6510bf1 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Wed, 28 Aug 2019 09:34:52 -0400
Subject: fixed initial storedmarks

---
 src/client/views/nodes/FormattedTextBox.tsx | 4 ++++
 1 file changed, 4 insertions(+)

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

diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 36740fc66..1c5224e12 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -628,6 +628,10 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
             this.props.select(false);
         }
         else if (this.props.isOverlay) this._editorView!.focus();
+        var markerss = this._editorView!.state.storedMarks || (this._editorView!.state.selection.$to.parentOffset && this._editorView!.state.selection.$from.marks());
+        let newMarks = [...(markerss ? markerss.filter(m => m.type !== schema.marks.user_mark) : []), schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail })];
+        this._editorView!.state.storedMarks = newMarks;
+
     }
 
     componentWillUnmount() {
-- 
cgit v1.2.3-70-g09d2


From 4b7672c75fe5cdf6afe534e67213917b24980c3e Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Wed, 28 Aug 2019 15:02:20 -0400
Subject: added better support for usermarks and fledliging for accept changes.

---
 src/client/util/RichTextSchema.tsx           | 14 ++++++---
 src/client/views/nodes/FormattedTextBox.scss | 17 ++++++++++
 src/client/views/nodes/FormattedTextBox.tsx  | 47 +++++++++++++++++++++++++---
 3 files changed, 69 insertions(+), 9 deletions(-)

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

diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx
index 6c06cec4d..f567d803e 100644
--- a/src/client/util/RichTextSchema.tsx
+++ b/src/client/util/RichTextSchema.tsx
@@ -333,12 +333,18 @@ export const marks: { [index: string]: MarkSpec } = {
     // the id of the user who entered the text
     user_mark: {
         attrs: {
-            userid: { default: "" }
+            userid: { default: "" },
+            hide_users: { default: [] },
+            opened: { default: false }
         },
+        group: "inline",
+        inclusive: false,
         toDOM(node: any) {
-            return ['span', {
-                style: `background: ${node.attrs.userid.indexOf(Doc.CurrentUserEmail) === -1 ? "rgba(255, 255, 0, 0.267)" : undefined};`
-            }];
+            let hideUsers = node.attrs.hide_users;
+            let hidden = hideUsers.indexOf(node.attrs.userid) !== -1 || (hideUsers.length === 0 && node.attrs.userid !== Doc.CurrentUserEmail);
+            return hidden ?
+                ['span', { class: node.attrs.opened ? "userMarkOpen" : "userMark" }, 0] :
+                ['span', 0];
         }
     },
 
diff --git a/src/client/views/nodes/FormattedTextBox.scss b/src/client/views/nodes/FormattedTextBox.scss
index e93ceda21..03e81bfca 100644
--- a/src/client/views/nodes/FormattedTextBox.scss
+++ b/src/client/views/nodes/FormattedTextBox.scss
@@ -67,6 +67,23 @@
     font-style: italic;
 }
 
+.userMarkOpen {
+    background:  rgba(255, 255, 0, 0.267);
+    display: inline;
+}
+.userMark {
+    background:  rgba(255, 255, 0, 0.267);
+    font-size: 2px;
+    display: inline-grid;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+    width:10px;
+    min-height:10px;
+    text-align:center;
+    align-content: center;
+}
+
 ol { counter-reset: deci 0;}
 .decimal-ol { counter-reset: deci 0; p { display: inline }; font-size: 24 }
 .decimal2-ol {counter-reset: deci2; p { display: inline }; font-size: 18 }
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 1c5224e12..146281f2b 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -5,8 +5,8 @@ import { observer } from "mobx-react";
 import { baseKeymap } from "prosemirror-commands";
 import { history } from "prosemirror-history";
 import { keymap } from "prosemirror-keymap";
-import { Fragment, Node, Node as ProsNode, NodeType, Slice, Mark } from "prosemirror-model";
-import { EditorState, Plugin, Transaction, TextSelection } from "prosemirror-state";
+import { Fragment, Node, Node as ProsNode, NodeType, Slice, Mark, ResolvedPos } from "prosemirror-model";
+import { EditorState, Plugin, Transaction, TextSelection, NodeSelection } from "prosemirror-state";
 import { EditorView } from "prosemirror-view";
 import { DateField } from '../../../new_fields/DateField';
 import { Doc, DocListCast, Opt, WidthSym } from "../../../new_fields/Doc";
@@ -645,9 +645,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
         document.removeEventListener("paste", this.paste);
     }
 
-    _down = false;
     onPointerDown = (e: React.PointerEvent): void => {
-        this._down = true;
         if (this.props.onClick && e.button === 0) {
             e.preventDefault();
         }
@@ -709,8 +707,47 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
         }
     }
 
+    findUserMark(marks: Mark[]) {
+        return marks.find(m => m.attrs && m.attrs.userid && m.attrs.userid !== Doc.CurrentUserEmail);
+    }
+    findStartOfMark(rpos: ResolvedPos) {
+        let before = 0;
+        let nbef = rpos.nodeBefore;
+        while (nbef && this.findUserMark(nbef.marks)) {
+            before += nbef.nodeSize;
+            rpos = this._editorView!.state.doc.resolve(rpos.pos - nbef.nodeSize);
+            rpos && (nbef = rpos.nodeBefore);
+        }
+        return before;
+    }
+    findEndOfMark(rpos: ResolvedPos) {
+        let after = 0;
+        let naft = rpos.nodeAfter;
+        while (naft && this.findUserMark(naft.marks)) {
+            after += naft.nodeSize;
+            rpos = this._editorView!.state.doc.resolve(rpos.pos + naft.nodeSize);
+            rpos && (naft = rpos.nodeAfter);
+        }
+        return after;
+    }
+
     onPointerUp = (e: React.PointerEvent): void => {
-        this._down = false;
+        let view = this._editorView!;
+        const pos = view.posAtCoords({ left: e.clientX, top: e.clientY });
+        const rpos = pos && view.state.doc.resolve(pos.pos);
+        if (pos && rpos && view.state.selection.$from === view.state.selection.$to) {
+            let nbef = this.findStartOfMark(rpos);
+            let naft = this.findEndOfMark(rpos);
+            const spos = view.state.doc.resolve(pos.pos - nbef);
+            const epos = view.state.doc.resolve(pos.pos + naft);
+            let ts = new TextSelection(spos, epos);
+            let child = rpos.nodeBefore;
+            let mark = child && this.findUserMark(child.marks);
+            if (mark && child && nbef && naft) {
+                let nmark = view.state.schema.marks.user_mark.create({ ...mark.attrs, userid: e.button === 2 ? Doc.CurrentUserEmail : mark.attrs.userid, opened: e.button === 2 ? false : !mark.attrs.opened });
+                view.dispatch(view.state.tr.setSelection(ts).removeMark(ts.from, ts.to, nmark).addMark(ts.from, ts.to, nmark).setSelection(new TextSelection(epos, epos)));
+            }
+        }
         if (e.buttons === 1 && this.props.isSelected() && !e.altKey) {
             e.stopPropagation();
         }
-- 
cgit v1.2.3-70-g09d2

