From a37faf30652c6c593923198ad34e54377e670caf Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Wed, 5 Jun 2019 08:09:10 -0400
Subject: fixed full screen text bug.  cleaned up imports

---
 src/client/views/TemplateMenu.tsx | 11 +++++------
 1 file changed, 5 insertions(+), 6 deletions(-)

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

diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx
index e5b679e24..3288abd90 100644
--- a/src/client/views/TemplateMenu.tsx
+++ b/src/client/views/TemplateMenu.tsx
@@ -1,12 +1,11 @@
-import { observable, computed, action, trace } from "mobx";
-import React = require("react");
+import { action, observable } from "mobx";
 import { observer } from "mobx-react";
+import { Doc } from "../../new_fields/Doc";
+import { List } from "../../new_fields/List";
 import './DocumentDecorations.scss';
-import { Template } from "./Templates";
 import { DocumentView } from "./nodes/DocumentView";
-import { List } from "../../new_fields/List";
-import { Doc } from "../../new_fields/Doc";
-import { NumCast } from "../../new_fields/Types";
+import { Template } from "./Templates";
+import React = require("react");
 const higflyout = require("@hig/flyout");
 export const { anchorPoints } = higflyout;
 export const Flyout = higflyout.default;
-- 
cgit v1.2.3-70-g09d2


From f74e512e500252ad76d77935e7aacbf72cb0dd9c Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Mon, 17 Jun 2019 14:41:21 -0400
Subject: added dropping on text as colleciton.

---
 src/client/views/TemplateMenu.tsx                  |  2 +-
 .../views/collections/CollectionSchemaView.tsx     | 30 ++++++++++------------
 .../views/collections/CollectionStackingView.tsx   |  1 +
 src/client/views/nodes/DocumentView.tsx            |  4 +--
 src/client/views/nodes/FormattedTextBox.tsx        | 28 ++++++++++++++++++--
 5 files changed, 44 insertions(+), 21 deletions(-)

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

diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx
index 3288abd90..a9bc4d3d2 100644
--- a/src/client/views/TemplateMenu.tsx
+++ b/src/client/views/TemplateMenu.tsx
@@ -45,7 +45,7 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> {
             if (template.Name === "Bullet") {
                 let topDocView = this.props.docs[0];
                 topDocView.addTemplate(template);
-                topDocView.props.Document.subBulletDocs = new List<Doc>(this.props.docs.filter(v => v !== topDocView).map(v => v.props.Document.proto!));
+                topDocView.props.Document.subBulletDocs = new List<Doc>(this.props.docs.filter(v => v !== topDocView).map(v => v.props.Document));
             } else {
                 this.props.docs.map(d => d.addTemplate(template));
             }
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index 7cc00ce07..4b46c73c1 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -2,36 +2,33 @@ import React = require("react");
 import { library } from '@fortawesome/fontawesome-svg-core';
 import { faCog, faPlus } from '@fortawesome/free-solid-svg-icons';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { action, computed, observable, untracked, runInAction, trace } from "mobx";
+import { action, computed, observable, trace, untracked } from "mobx";
 import { observer } from "mobx-react";
 import ReactTable, { CellInfo, ComponentPropsGetterR, ReactTableDefaults } from "react-table";
-import { MAX_ROW_HEIGHT } from '../../views/globalCssVariables.scss';
 import "react-table/react-table.css";
+import { Doc, DocListCast, DocListCastAsync, Field } from "../../../new_fields/Doc";
+import { Id } from "../../../new_fields/FieldSymbols";
+import { List } from "../../../new_fields/List";
+import { listSpec } from "../../../new_fields/Schema";
+import { Cast, FieldValue, NumCast, StrCast } from "../../../new_fields/Types";
 import { emptyFunction, returnFalse, returnZero } from "../../../Utils";
+import { Docs } from "../../documents/Documents";
+import { Gateway } from "../../northstar/manager/Gateway";
 import { SetupDrag } from "../../util/DragManager";
 import { CompileScript } from "../../util/Scripting";
 import { Transform } from "../../util/Transform";
-import { COLLECTION_BORDER_WIDTH } from "../../views/globalCssVariables.scss";
+import { COLLECTION_BORDER_WIDTH, MAX_ROW_HEIGHT } from '../../views/globalCssVariables.scss';
+import { ContextMenu } from "../ContextMenu";
 import { anchorPoints, Flyout } from "../DocumentDecorations";
 import '../DocumentDecorations.scss';
 import { EditableView } from "../EditableView";
 import { DocumentView } from "../nodes/DocumentView";
 import { FieldView, FieldViewProps } from "../nodes/FieldView";
+import { CollectionPDFView } from "./CollectionPDFView";
 import "./CollectionSchemaView.scss";
 import { CollectionSubView } from "./CollectionSubView";
-import { Opt, Field, Doc, DocListCastAsync, DocListCast } from "../../../new_fields/Doc";
-import { Cast, FieldValue, NumCast, StrCast, BoolCast } from "../../../new_fields/Types";
-import { listSpec } from "../../../new_fields/Schema";
-import { List } from "../../../new_fields/List";
-import { Id } from "../../../new_fields/FieldSymbols";
-import { Gateway } from "../../northstar/manager/Gateway";
-import { Docs } from "../../documents/Documents";
-import { ContextMenu } from "../ContextMenu";
-import { CollectionView } from "./CollectionView";
-import { CollectionPDFView } from "./CollectionPDFView";
 import { CollectionVideoView } from "./CollectionVideoView";
-import { SelectionManager } from "../../util/SelectionManager";
-import { undoBatch } from "../../util/UndoManager";
+import { CollectionView } from "./CollectionView";
 
 
 library.add(faCog);
@@ -389,6 +386,7 @@ interface CollectionSchemaPreviewProps {
     CollectionView: CollectionView | CollectionPDFView | CollectionVideoView;
     getTransform: () => Transform;
     addDocument: (document: Doc, allowDuplicates?: boolean) => boolean;
+    moveDocument: (document: Doc, target: Doc, addDoc: ((doc: Doc) => boolean)) => boolean;
     removeDocument: (document: Doc) => boolean;
     active: () => boolean;
     whenActiveChanged: (isActive: boolean) => void;
@@ -424,7 +422,7 @@ export class CollectionSchemaPreview extends React.Component<CollectionSchemaPre
             {!this.props.Document || !this.props.width ? (null) : (
                 <div className="collectionSchemaView-previewDoc" style={{ transform: `translate(${this.centeringOffset}px, 0px)`, height: "100%" }}>
                     <DocumentView Document={this.props.Document} isTopMost={false} selectOnLoad={false}
-                        addDocument={this.props.addDocument} removeDocument={this.props.removeDocument}
+                        addDocument={this.props.addDocument} removeDocument={this.props.removeDocument} moveDocument={this.props.moveDocument}
                         ScreenToLocalTransform={this.getTransform}
                         ContentScaling={this.contentScaling}
                         PanelWidth={this.PanelWidth} PanelHeight={this.PanelHeight}
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index ef12545b8..ede37534a 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -81,6 +81,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
                     getTransform={dxf}
                     CollectionView={this.props.CollectionView}
                     addDocument={this.props.addDocument}
+                    moveDocument={this.props.moveDocument}
                     removeDocument={this.props.removeDocument}
                     active={this.props.active}
                     whenActiveChanged={this.props.whenActiveChanged}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 856fdab7f..8ece7d67f 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -285,8 +285,8 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                     let expandedProtoDocs = expandedDocs.map(doc => Doc.GetProto(doc));
                     let maxLocation = StrCast(this.props.Document.maximizeLocation, "inPlace");
                     let getDispDoc = (target: Doc) => Object.getOwnPropertyNames(target).indexOf("isPrototype") === -1 ? target : Doc.MakeDelegate(target);
-                    if (altKey) {
-                        maxLocation = this.props.Document.maximizeLocation = (maxLocation === "inPlace" || !maxLocation ? "inTab" : "inPlace");
+                    if (altKey || ctrlKey) {
+                        maxLocation = this.props.Document.maximizeLocation = (ctrlKey ? maxLocation : (maxLocation === "inPlace" || !maxLocation ? "inTab" : "inPlace"));
                         if (!maxLocation || maxLocation === "inPlace") {
                             let hadView = expandedDocs.length === 1 && DocumentManager.Instance.getDocumentView(expandedProtoDocs[0], this.props.ContainingCollectionView);
                             let wasMinimized = !hadView && expandedDocs.reduce((min, d) => !min && !BoolCast(d.IsMinimized, false), false);
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index e5a43c60a..7a9593a60 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -8,10 +8,10 @@ import { keymap } from "prosemirror-keymap";
 import { NodeType } from 'prosemirror-model';
 import { EditorState, Plugin, Transaction } from "prosemirror-state";
 import { EditorView } from "prosemirror-view";
-import { Doc, Opt } from "../../../new_fields/Doc";
+import { Doc, Opt, DocListCast } from "../../../new_fields/Doc";
 import { Id } from '../../../new_fields/FieldSymbols';
 import { RichTextField } from "../../../new_fields/RichTextField";
-import { createSchema, makeInterface } from "../../../new_fields/Schema";
+import { createSchema, makeInterface, listSpec } from "../../../new_fields/Schema";
 import { BoolCast, Cast, NumCast, StrCast } from "../../../new_fields/Types";
 import { DocServer } from "../../DocServer";
 import { Docs } from '../../documents/Documents';
@@ -30,6 +30,8 @@ import { InkingControl } from "../InkingControl";
 import { FieldView, FieldViewProps } from "./FieldView";
 import "./FormattedTextBox.scss";
 import React = require("react");
+import { List } from '../../../new_fields/List';
+import { Templates } from '../Templates';
 
 library.add(faEdit);
 library.add(faSmile);
@@ -139,6 +141,28 @@ 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) {
+                let ldocs = Cast(this.props.Document.subBulletDocs, listSpec(Doc));
+                if (!ldocs) {
+                    this.props.Document.subBulletDocs = new List<Doc>([]);
+                }
+                ldocs = Cast(this.props.Document.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.props.Document.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;
+                    })
+                }
+            }
         }
     }
 
-- 
cgit v1.2.3-70-g09d2


From db34b52b66311a72f986a0406acdb935369d264f Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Mon, 1 Jul 2019 12:38:51 -0400
Subject: added some context menu undo's

---
 src/client/views/TemplateMenu.tsx                   |  2 ++
 src/client/views/nodes/DocumentView.tsx             | 21 ++++++++++++++++++---
 .../views/presentationview/PresentationView.tsx     |  1 +
 3 files changed, 21 insertions(+), 3 deletions(-)

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

diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx
index a9bc4d3d2..a53c8749a 100644
--- a/src/client/views/TemplateMenu.tsx
+++ b/src/client/views/TemplateMenu.tsx
@@ -6,6 +6,7 @@ import './DocumentDecorations.scss';
 import { DocumentView } from "./nodes/DocumentView";
 import { Template } from "./Templates";
 import React = require("react");
+import { undoBatch } from "../util/UndoManager";
 const higflyout = require("@hig/flyout");
 export const { anchorPoints } = higflyout;
 export const Flyout = higflyout.default;
@@ -39,6 +40,7 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> {
         super(props);
     }
 
+    @undoBatch
     @action
     toggleTemplate = (event: React.ChangeEvent<HTMLInputElement>, template: Template): void => {
         if (event.target.checked) {
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 9edde896f..a6f324a04 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -393,8 +393,13 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         this._lastTap = Date.now();
     }
 
-    deleteClicked = (): void => { this.props.removeDocument && this.props.removeDocument(this.props.Document); };
-    fieldsClicked = (): void => { let kvp = Docs.KVPDocument(this.props.Document, { width: 300, height: 300 }); this.props.addDocTab(kvp, this.dataDoc, "onRight"); };
+    @undoBatch
+    deleteClicked = (): void => { SelectionManager.DeselectAll(); this.props.removeDocument && this.props.removeDocument(this.props.Document); }
+
+    @undoBatch
+    fieldsClicked = (): void => { let kvp = Docs.KVPDocument(this.props.Document, { width: 300, height: 300 }); this.props.addDocTab(kvp, this.dataDoc, "onRight"); }
+
+    @undoBatch
     makeBtnClicked = (): void => {
         let doc = Doc.GetProto(this.props.Document);
         doc.isButton = !BoolCast(doc.isButton, false);
@@ -407,6 +412,8 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
             doc.nativeWidth = doc.nativeHeight = undefined;
         }
     }
+
+    @undoBatch
     public fullScreenClicked = (): void => {
         CollectionDockingView.Instance && CollectionDockingView.Instance.OpenFullScreen(this);
         SelectionManager.DeselectAll();
@@ -467,6 +474,8 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         this.templates = this.templates;
     }
 
+    @undoBatch
+    @action
     freezeNativeDimensions = (): void => {
         let proto = Doc.GetProto(this.props.Document);
         if (proto.ignoreAspect === undefined && !proto.nativeWidth) {
@@ -477,6 +486,12 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         proto.ignoreAspect = !BoolCast(proto.ignoreAspect, false);
     }
 
+    @undoBatch
+    @action
+    toggleLockPosition = (): void => {
+        this.props.Document.lockedPosition = BoolCast(this.props.Document.lockedPosition) ? undefined : true;
+    }
+
     @action
     onContextMenu = async (e: React.MouseEvent): Promise<void> => {
         e.persist();
@@ -499,7 +514,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         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: "edit" });
         cm.addItem({ description: "Pin to Pres", event: () => PresentationView.Instance.PinDoc(this.props.Document), icon: "map-pin" });
-        cm.addItem({ description: BoolCast(this.props.Document.lockedPosition) ? "Unlock Pos" : "Lock Pos", event: () => this.props.Document.lockedPosition = BoolCast(this.props.Document.lockedPosition) ? undefined : true, icon: BoolCast(this.props.Document.lockedPosition) ? "unlock" : "lock" });
+        cm.addItem({ description: BoolCast(this.props.Document.lockedPosition) ? "Unlock Pos" : "Lock Pos", event: this.toggleLockPosition, icon: BoolCast(this.props.Document.lockedPosition) ? "unlock" : "lock" });
         cm.addItem({ description: this.props.Document.isButton ? "Remove Button" : "Make Button", event: this.makeBtnClicked, icon: "concierge-bell" });
         cm.addItem({
             description: "Find aliases", event: async () => {
diff --git a/src/client/views/presentationview/PresentationView.tsx b/src/client/views/presentationview/PresentationView.tsx
index 20d0e113a..a3fa553b7 100644
--- a/src/client/views/presentationview/PresentationView.tsx
+++ b/src/client/views/presentationview/PresentationView.tsx
@@ -494,6 +494,7 @@ export class PresentationView extends React.Component<PresViewProps>  {
     /**
      * Adds a document to the presentation view
      **/
+    @undoBatch
     @action
     public PinDoc(doc: Doc) {
         //add this new doc to props.Document
-- 
cgit v1.2.3-70-g09d2


From ab2b2317e601b9e440f9c48b4639c143d5187949 Mon Sep 17 00:00:00 2001
From: Sam Wilkins <samwilkins333@gmail.com>
Date: Mon, 1 Jul 2019 19:29:15 -0400
Subject: added tooltips and improved acm scraping

---
 src/client/views/DocumentDecorations.tsx |  2 +-
 src/client/views/GlobalKeyHandler.ts     |  2 +-
 src/client/views/MainView.tsx            |  6 ++--
 src/client/views/TemplateMenu.tsx        |  2 +-
 src/scraping/acm/index.js                | 56 +++++++++++++++++++++++++-------
 src/scraping/acm/results.txt             | 34 +++++++++++--------
 6 files changed, 71 insertions(+), 31 deletions(-)

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

diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 61e9d209a..e1eff5cdc 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -692,7 +692,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
                 {this._edtingTitle ?
                     <input ref={this.keyinput} className="title" type="text" name="dynbox" value={this._title} onBlur={this.titleBlur} onChange={this.titleChanged} onKeyPress={this.titleEntered} /> :
                     <div className="title" onPointerDown={this.onTitleDown} ><span>{`${this.selectionTitle}`}</span></div>}
-                <div className="documentDecorations-closeButton" onPointerDown={this.onCloseDown}>X</div>
+                <div className="documentDecorations-closeButton" title="Close Document" onPointerDown={this.onCloseDown}>X</div>
                 <div id="documentDecorations-topLeftResizer" className="documentDecorations-resizer" onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()}></div>
                 <div id="documentDecorations-topResizer" className="documentDecorations-resizer" onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()}></div>
                 <div id="documentDecorations-topRightResizer" className="documentDecorations-resizer" onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()}></div>
diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts
index e467d7c61..4c72bd683 100644
--- a/src/client/views/GlobalKeyHandler.ts
+++ b/src/client/views/GlobalKeyHandler.ts
@@ -13,7 +13,7 @@ type KeyControlInfo = {
 };
 
 export default class KeyManager {
-    public static Handler: KeyManager = new KeyManager();
+    public static Instance: KeyManager = new KeyManager();
     private router = new Map<string, KeyHandler>();
 
     constructor() {
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index fb88c284f..a9d75d8cc 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -64,8 +64,8 @@ export class MainView extends React.Component {
     }
 
     componentWillMount() {
-        window.removeEventListener("keydown", KeyManager.Handler.handle);
-        window.addEventListener("keydown", KeyManager.Handler.handle);
+        window.removeEventListener("keydown", KeyManager.Instance.handle);
+        window.addEventListener("keydown", KeyManager.Instance.handle);
 
         window.removeEventListener("pointerdown", this.pointerDown);
         window.addEventListener("pointerdown", this.pointerDown);
@@ -78,7 +78,7 @@ export class MainView extends React.Component {
     pointerUp = (e: PointerEvent) => this.isPointerDown = false;
 
     componentWillUnMount() {
-        window.removeEventListener("keydown", KeyManager.Handler.handle);
+        window.removeEventListener("keydown", KeyManager.Instance.handle);
         window.removeEventListener("pointerdown", this.pointerDown);
         window.removeEventListener("pointerup", this.pointerUp);
     }
diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx
index a9bc4d3d2..a1d59484a 100644
--- a/src/client/views/TemplateMenu.tsx
+++ b/src/client/views/TemplateMenu.tsx
@@ -79,7 +79,7 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> {
 
         return (
             <div className="templating-menu" >
-                <div className="templating-button" onClick={() => this.toggleTemplateActivity()}>+</div>
+                <div title="Template Options" className="templating-button" onClick={() => this.toggleTemplateActivity()}>+</div>
                 <ul id="template-list" style={{ display: this._hidden ? "none" : "block" }}>
                     {templateMenu}
                 </ul>
diff --git a/src/scraping/acm/index.js b/src/scraping/acm/index.js
index ff4b099e7..ad0f844ba 100644
--- a/src/scraping/acm/index.js
+++ b/src/scraping/acm/index.js
@@ -10,6 +10,17 @@ const {
 const driver_pause = 500; // milliseconds
 const sample_line_char_max = 100; // characters
 const target_browser = 'chrome';
+const tab_map = {
+    abstract: "11",
+    authors: "14",
+    references: "15",
+    cited_by: "16",
+    index_terms: "17",
+    publication: "18",
+    reviews: "19",
+    comments: "20",
+    table_of_contents: "21"
+};
 
 // GENERAL UTILITY FUNCTIONS
 
@@ -32,14 +43,18 @@ function log_snippet(result, quotes = true) {
             snippet = quotes ? `"${snippet}"` : snippet;
             break;
         case "object":
-            snippet = result.map(res => {
-                switch (typeof res) {
-                    case "string":
-                        return res.substring(0, sample_line_char_max / result.length);
-                    case "object":
-                        return res[Object.keys(res)[0]];
-                }
-            }).join(', ');
+            if (Array.isArray(result)) {
+                snippet = result.map(res => {
+                    switch (typeof res) {
+                        case "string":
+                            return res.substring(0, sample_line_char_max / result.length);
+                        case "object":
+                            return res[Object.keys(res)[0]];
+                    }
+                }).join(', ');
+            } else {
+                snippet = result[Object.keys(result)[0]];
+            }
     }
     console.log(snippet);
     return result;
@@ -57,6 +72,10 @@ async function click_on(ref) {
     await driver.sleep(driver_pause);
 }
 
+async function click_on_acm_tab(target) {
+    await click_on(`//*[@id="tab-10${tab_map[target]}-btnInnerEl"]/span`);
+}
+
 async function locate(ref, multiple = false) {
     let locator = ref.startsWith("//") ? By.xpath(ref) : By.id(ref);
     return await multiple ? driver.findElements(locator) : driver.findElement(locator);
@@ -84,8 +103,6 @@ async function logged_assign(key, value) {
 // TEXT SCRAPING
 
 async function read_authors() {
-    await click_on('//*[@id="tab-1014-btnInnerEl"]/span');
-
     let authors = await text_of('//*[@id="tabpanel-1009-body"]');
     let sanitize = line => line.length > 0 && !(line.startsWith("No contact information") || line.startsWith("View colleagues of") || line.startsWith("Bibliometrics:"));
     let author_lines = authors.split("\n").map(line => line.trim()).filter(sanitize);
@@ -106,6 +123,17 @@ async function read_authors() {
     return all_authors;
 }
 
+async function read_publication() {
+    let publciation_elements = (await text_of("source-body")).split("\n");
+    let publication_module = {};
+    for (let element of publciation_elements) {
+        if (element.startsWith("Title")) {
+            publication_module.title = element.substring(6);
+        }
+    }
+    return publication_module;
+}
+
 // JSON / DASH CONVERSION AND EXPORT
 
 function parse_authors(metadata) {
@@ -134,7 +162,7 @@ function write_results() {
     results.forEach(res => output += (JSON.stringify(res, null, 4) + "\n"));
 
     writeFile("./results.txt", output, function errorHandler(exception) {
-        console.log(exception || "scraped references successfully written as JSON to ./results.txt\n");
+        console.log(exception || "scraped references successfully written as JSON to ./results.txt");
     });
 }
 
@@ -157,12 +185,18 @@ async function scrape_targets(error, data) {
             let id = references[i];
             let url = `https://dl.acm.org/citation.cfm?id=${id}`;
             console.log(`\nscraping ${i + 1}/${quota} (${id})`);
+
             await navigate_to(url);
 
             logged_assign("url", url);
             logged_assign("title", await text_of('//*[@id="divmain"]/div/h1'));
             logged_assign("abstract", (await text_of_all("abstract-body")).join(" "));
+
+            await click_on_acm_tab("authors");
             logged_assign("authors", (await read_authors()).map(parse_authors));
+
+            await click_on_acm_tab("publication");
+            logged_assign("publication", await read_publication());
         } catch (e) {
             console.log(e);
             await driver.quit();
diff --git a/src/scraping/acm/results.txt b/src/scraping/acm/results.txt
index fffa7ff51..ba66d61a7 100644
--- a/src/scraping/acm/results.txt
+++ b/src/scraping/acm/results.txt
@@ -10,10 +10,10 @@
             "publication_count": 1,
             "citation_count": 179,
             "available_for_download": 1,
-            "downloads_6_weeks": 130,
-            "downloads_12_months": 1004,
-            "downloads_cumulative": 9792,
-            "average_downloads_per_article": 9792,
+            "downloads_6_weeks": 123,
+            "downloads_12_months": 922,
+            "downloads_cumulative": 9793,
+            "average_downloads_per_article": 9793,
             "average_citations_per_article": 179
         },
         {
@@ -23,10 +23,10 @@
             "publication_count": 5,
             "citation_count": 196,
             "available_for_download": 1,
-            "downloads_6_weeks": 130,
-            "downloads_12_months": 1004,
-            "downloads_cumulative": 9792,
-            "average_downloads_per_article": 9792,
+            "downloads_6_weeks": 123,
+            "downloads_12_months": 922,
+            "downloads_cumulative": 9793,
+            "average_downloads_per_article": 9793,
             "average_citations_per_article": 39.2
         },
         {
@@ -36,13 +36,16 @@
             "publication_count": 2,
             "citation_count": 188,
             "available_for_download": 2,
-            "downloads_6_weeks": 130,
-            "downloads_12_months": 1009,
-            "downloads_cumulative": 10023,
-            "average_downloads_per_article": 5011.5,
+            "downloads_6_weeks": 123,
+            "downloads_12_months": 927,
+            "downloads_cumulative": 10024,
+            "average_downloads_per_article": 5012,
             "average_citations_per_article": 94
         }
-    ]
+    ],
+    "publication": {
+        "title": "Journal of the ACM (JACM) JACM Homepage table of contents archive"
+    }
 }
 {
     "url": "https://dl.acm.org/citation.cfm?id=2412979",
@@ -62,5 +65,8 @@
             "average_downloads_per_article": 0,
             "average_citations_per_article": 0
         }
-    ]
+    ],
+    "publication": {
+        "title": "IEEE Transactions on Software Engineering table of contents archive"
+    }
 }
-- 
cgit v1.2.3-70-g09d2


From 16822d88f981e7a86729d942a92b6ad8590680e4 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Mon, 1 Jul 2019 22:32:44 -0400
Subject: fixed title template view issue

---
 src/client/views/TemplateMenu.tsx                      | 8 ++++++++
 src/client/views/Templates.tsx                         | 4 ++--
 src/client/views/collections/CollectionDockingView.tsx | 2 +-
 src/client/views/nodes/DocumentView.tsx                | 5 +++++
 4 files changed, 16 insertions(+), 3 deletions(-)

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

diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx
index d63f45e5a..1b32f0ddd 100644
--- a/src/client/views/TemplateMenu.tsx
+++ b/src/client/views/TemplateMenu.tsx
@@ -64,6 +64,13 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> {
         }
     }
 
+    @undoBatch
+    @action
+    clearTemplates = (event: React.MouseEvent) => {
+        this.props.docs.map(d => d.clearTemplates());
+        Array.from(this.props.templates.keys()).map(t => this.props.templates.set(t, false));
+    }
+
     @action
     componentWillReceiveProps(nextProps: TemplateMenuProps) {
         // this._templates = nextProps.templates;
@@ -84,6 +91,7 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> {
                 <div title="Template Options" className="templating-button" onClick={() => this.toggleTemplateActivity()}>+</div>
                 <ul id="template-list" style={{ display: this._hidden ? "none" : "block" }}>
                     {templateMenu}
+                    <button style={{ display: this._hidden ? "none" : "block" }} onClick={this.clearTemplates}>Clear</button>
                 </ul>
             </div>
         );
diff --git a/src/client/views/Templates.tsx b/src/client/views/Templates.tsx
index 5bb8d454a..4843a70a6 100644
--- a/src/client/views/Templates.tsx
+++ b/src/client/views/Templates.tsx
@@ -50,7 +50,7 @@ export namespace Templates {
     export const Title = new Template("Title", TemplatePosition.InnerTop,
         `<div>
             <div style="height:25px; width:100%; background-color: rgba(0, 0, 0, .4); color: white; z-index: 100">
-                <span style="text-align:center;width:100%;font-size:20px;position:absolute;overflow:hidden;white-space:nowrap;text-overflow:ellipsis">{props.DataDoc.title}</span>
+                <span style="text-align:center;width:100%;font-size:20px;position:absolute;overflow:hidden;white-space:nowrap;text-overflow:ellipsis">{props.Document.title}</span>
             </div>
             <div style="height:calc(100% - 25px);">
                 <div style="width:100%;overflow:auto">{layout}</div>
@@ -58,7 +58,7 @@ export namespace Templates {
         </div>` );
 
     export const Header = new Template("Header", TemplatePosition.InnerTop,
-        `< div style = "display:flex; flex-direction:column; height:100%;" >
+        `<div style = "display:flex; flex-direction:column; height:100%;" >
             <div style="width:100%; background-color: rgba(0, 0, 0, .4); color: white; ">
                 <FormattedTextBox {...props} height={"min-content"} color={"white"} fieldKey={"header"} />
             </div>
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index ad5472a4a..8724216f5 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -269,7 +269,7 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
         var cur = this._containerRef.current;
 
         // bcz: since GoldenLayout isn't a React component itself, we need to notify it to resize when its document container's size has changed
-        this._goldenLayout.updateSize(cur!.getBoundingClientRect().width, cur!.getBoundingClientRect().height);
+        this._goldenLayout && this._goldenLayout.updateSize(cur!.getBoundingClientRect().width, cur!.getBoundingClientRect().height);
     }
 
     @action
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 687c7f73d..3673cb0e2 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -473,6 +473,11 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         }
         this.templates = this.templates;
     }
+    @action
+    clearTemplates = () => {
+        this.templates.length = 0;
+        this.templates = this.templates;
+    }
 
     @undoBatch
     @action
-- 
cgit v1.2.3-70-g09d2

