From 6f985b10f71ace2303b669d4e2a1165ff3a29eda Mon Sep 17 00:00:00 2001
From: usodhi <61431818+usodhi@users.noreply.github.com>
Date: Fri, 10 Jul 2020 18:24:32 +0530
Subject: added _chromeStatus to playground fields

---
 src/client/views/MainView.tsx | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

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

diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 81195b550..1bda9e9c2 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -88,7 +88,7 @@ export class MainView extends React.Component {
     public isPointerDown = false;
 
     componentDidMount() {
-        DocServer.setPlaygroundFields(["dataTransition", "_viewTransition", "_panX", "_panY", "_viewScale", "_viewType"]); // can play with these fields on someone else's
+        DocServer.setPlaygroundFields(["dataTransition", "_viewTransition", "_panX", "_panY", "_viewScale", "_viewType", "_chromeStatus"]); // can play with these fields on someone else's
 
         const tag = document.createElement('script');
 
@@ -454,9 +454,6 @@ export class MainView extends React.Component {
                     <button className="mainView-settings" key="settings" onClick={() => SettingsManager.Instance.open()}>
                         <FontAwesomeIcon icon="cog" size="lg" />
                     </button>
-                    <button className="mainView-settings" key="groups" onClick={() => GroupManager.Instance.open()}>
-                        <FontAwesomeIcon icon="columns" size="lg" />
-                    </button>
                 </div>
             </div>
             {this.docButtons}
-- 
cgit v1.2.3-70-g09d2


From 7b7d83f6f7070334fdfc4dd7cca03699b8e21078 Mon Sep 17 00:00:00 2001
From: usodhi <61431818+usodhi@users.noreply.github.com>
Date: Mon, 20 Jul 2020 19:21:54 +0530
Subject: fixed some addonly stuff + added annotations to playground fields +
 recursively distributes acls + some modal stuff

---
 src/client/apis/GoogleAuthenticationManager.tsx    |  7 +--
 .../apis/HypothesisAuthenticationManager.tsx       |  6 ++-
 src/client/util/GroupManager.scss                  |  2 +-
 src/client/util/GroupManager.tsx                   |  6 +--
 src/client/util/SettingsManager.tsx                |  4 +-
 src/client/util/SharingManager.tsx                 | 58 ++++++++++++++++++----
 src/client/views/DocComponent.tsx                  | 26 ++++++++--
 src/client/views/MainView.tsx                      |  2 +-
 src/client/views/collections/CollectionView.tsx    | 25 +++++++++-
 src/fields/Doc.ts                                  | 14 +++---
 src/fields/util.ts                                 | 21 ++++----
 11 files changed, 128 insertions(+), 43 deletions(-)

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

diff --git a/src/client/apis/GoogleAuthenticationManager.tsx b/src/client/apis/GoogleAuthenticationManager.tsx
index 5a2bdb13b..117d1fa1e 100644
--- a/src/client/apis/GoogleAuthenticationManager.tsx
+++ b/src/client/apis/GoogleAuthenticationManager.tsx
@@ -146,7 +146,7 @@ export default class GoogleAuthenticationManager extends React.Component<{}> {
 
     private get dialogueBoxStyle() {
         const borderColor = this.success === undefined ? "black" : this.success ? "green" : "red";
-        return { borderColor, transition: "0.2s borderColor ease" };
+        return { borderColor, transition: "0.2s borderColor ease", zIndex: 1002 };
     }
 
     render() {
@@ -155,9 +155,10 @@ export default class GoogleAuthenticationManager extends React.Component<{}> {
                 isDisplayed={this.openState}
                 interactive={true}
                 contents={this.renderPrompt}
-                overlayDisplayedOpacity={0.9}
+                // overlayDisplayedOpacity={0.9}
                 dialogueBoxStyle={this.dialogueBoxStyle}
-                closeOnExternalClick={() => this.isOpen = false}
+                overlayStyle={{ zIndex: 1001 }}
+                closeOnExternalClick={action(() => this.isOpen = false)}
             />
         );
     }
diff --git a/src/client/apis/HypothesisAuthenticationManager.tsx b/src/client/apis/HypothesisAuthenticationManager.tsx
index a7fcf86a4..c3e8d2fff 100644
--- a/src/client/apis/HypothesisAuthenticationManager.tsx
+++ b/src/client/apis/HypothesisAuthenticationManager.tsx
@@ -138,7 +138,7 @@ export default class HypothesisAuthenticationManager extends React.Component<{}>
 
     private get dialogueBoxStyle() {
         const borderColor = this.success === undefined ? "black" : this.success ? "green" : "red";
-        return { borderColor, transition: "0.2s borderColor ease" };
+        return { borderColor, transition: "0.2s borderColor ease", zIndex: 1002 };
     }
 
     render() {
@@ -147,8 +147,10 @@ export default class HypothesisAuthenticationManager extends React.Component<{}>
                 isDisplayed={this.openState}
                 interactive={true}
                 contents={this.renderPrompt}
-                overlayDisplayedOpacity={0.9}
+                // overlayDisplayedOpacity={0.9}
                 dialogueBoxStyle={this.dialogueBoxStyle}
+                overlayStyle={{ zIndex: 1001 }}
+                closeOnExternalClick={action(() => this.isOpen = false)}
             />
         );
     }
diff --git a/src/client/util/GroupManager.scss b/src/client/util/GroupManager.scss
index 34d4f40f8..51e4fa9e2 100644
--- a/src/client/util/GroupManager.scss
+++ b/src/client/util/GroupManager.scss
@@ -1,5 +1,5 @@
 .group-interface {
-    width: 550px;
+    width: 380px;
     height: 300px;
 
     .dialogue-box {
diff --git a/src/client/util/GroupManager.tsx b/src/client/util/GroupManager.tsx
index 12951f2ab..2e5ecc543 100644
--- a/src/client/util/GroupManager.tsx
+++ b/src/client/util/GroupManager.tsx
@@ -354,7 +354,7 @@ export default class GroupManager extends React.Component<{}> {
                 isDisplayed={this.createGroupModalOpen}
                 interactive={true}
                 contents={contents}
-                dialogueBoxStyle={{ width: "70%", height: "70%" }}
+                dialogueBoxStyle={{ width: "90%", height: "70%" }}
                 closeOnExternalClick={action(() => this.createGroupModalOpen = false)}
             />
         );
@@ -424,8 +424,8 @@ export default class GroupManager extends React.Component<{}> {
                 contents={this.groupInterface}
                 isDisplayed={this.isOpen}
                 interactive={true}
-                dialogueBoxDisplayedOpacity={this.dialogueBoxOpacity}
-                overlayDisplayedOpacity={this.overlayOpacity}
+                dialogueBoxStyle={{ zIndex: 1002 }}
+                overlayStyle={{ zIndex: 1001 }}
                 closeOnExternalClick={this.close}
             />
         );
diff --git a/src/client/util/SettingsManager.tsx b/src/client/util/SettingsManager.tsx
index fc5fdd869..90d59aa51 100644
--- a/src/client/util/SettingsManager.tsx
+++ b/src/client/util/SettingsManager.tsx
@@ -119,10 +119,10 @@ export default class SettingsManager extends React.Component<{}> {
                         <button onClick={this.togglePlaygroundMode}>{`${this.playgroundMode ? "Disable" : "Enable"} playground mode`}</button>
                         <button onClick={this.googleAuthorize} value="data">{`Link to Google`}</button>
                         <button onClick={this.hypothesisAuthorize} value="data">{`Link to Hypothes.is`}</button>
+                        <button onClick={() => GroupManager.Instance.open()}>Manage groups</button>
                         <button onClick={() => window.location.assign(Utils.prepend("/logout"))}>
                             {CurrentUserUtils.GuestWorkspace ? "Exit" : "Log Out"}
                         </button>
-                        <button onClick={() => GroupManager.Instance.open()}>Manage groups</button>
                     </div>
                     {this.settingsContent === "password" ?
                         <div className="settings-content">
@@ -155,8 +155,6 @@ export default class SettingsManager extends React.Component<{}> {
                 contents={this.settingsInterface}
                 isDisplayed={this.isOpen}
                 interactive={true}
-                dialogueBoxDisplayedOpacity={this.dialogueBoxOpacity}
-                overlayDisplayedOpacity={this.overlayOpacity}
                 closeOnExternalClick={this.close}
             />
         );
diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx
index fe7324d5c..8b3ac2613 100644
--- a/src/client/util/SharingManager.tsx
+++ b/src/client/util/SharingManager.tsx
@@ -1,13 +1,12 @@
 import { observable, runInAction, action } from "mobx";
 import * as React from "react";
 import MainViewModal from "../views/MainViewModal";
-import { Doc, Opt, DocListCastAsync } from "../../fields/Doc";
+import { Doc, Opt, DocListCastAsync, DataSym, DocListCast } from "../../fields/Doc";
 import { DocServer } from "../DocServer";
 import { Cast, StrCast } from "../../fields/Types";
 import * as RequestPromise from "request-promise";
 import { Utils } from "../../Utils";
 import "./SharingManager.scss";
-import { Id } from "../../fields/FieldSymbols";
 import { observer } from "mobx-react";
 import { library } from '@fortawesome/fontawesome-svg-core';
 import * as fa from '@fortawesome/free-solid-svg-icons';
@@ -82,6 +81,7 @@ export default class SharingManager extends React.Component<{}> {
             this.targetDoc = target.props.Document;
             DictationOverlay.Instance.hasActiveModal = true;
             this.isOpen = true;
+            this.permissions = SharingPermissions.Edit;
         }));
 
     }
@@ -127,9 +127,11 @@ export default class SharingManager extends React.Component<{}> {
 
         const target = this.targetDoc!;
         const ACL = `ACL-${StrCast(group.groupName)}`;
+        // fix this - not needed (here and setinternalsharing and removegroup)
+        // target[ACL] = permission;
+        // Doc.GetProto(target)[ACL] = permission;
 
-        target[ACL] = permission;
-        Doc.GetProto(target)[ACL] = permission;
+        this.distributeAcls(ACL, permission as SharingPermissions);
 
         group.docsShared ? DocListCastAsync(group.docsShared).then(resolved => Doc.IndexOf(target, resolved!) === -1 && (group.docsShared as List<Doc>).push(target)) : group.docsShared = new List<Doc>([target]);
 
@@ -170,7 +172,9 @@ export default class SharingManager extends React.Component<{}> {
             DocListCastAsync(group.docsShared).then(resolved => {
                 resolved?.forEach(doc => {
                     const ACL = `ACL-${StrCast(group.groupName)}`;
-                    doc[ACL] = "Not Shared";
+                    // doc[ACL] = doc[DataSym][ACL] = "Not Shared";
+
+                    this.distributeAcls(ACL, SharingPermissions.None, doc);
 
                     const members: string[] = JSON.parse(StrCast(group.members));
                     const users: ValidatedUser[] = this.users.filter(({ user: { email } }) => members.includes(email));
@@ -189,8 +193,10 @@ export default class SharingManager extends React.Component<{}> {
 
         const ACL = `ACL-${key}`;
 
-        target[ACL] = permission;
-        Doc.GetProto(target)[ACL] = permission;
+        // target[ACL] = permission;
+        // Doc.GetProto(target)[ACL] = permission;
+
+        this.distributeAcls(ACL, permission as SharingPermissions);
 
         if (permission !== SharingPermissions.None) {
             DocListCastAsync(notificationDoc[storage]).then(resolved => {
@@ -202,6 +208,40 @@ export default class SharingManager extends React.Component<{}> {
                 Doc.IndexOf(target, resolved!) !== -1 && Doc.RemoveDocFromList(notificationDoc, storage, target);
             });
         }
+    }
+
+    @action
+    distributeAcls = (key: string, acl: SharingPermissions, doc?: Doc) => {
+        const target = doc ? doc : this.targetDoc!;
+        const dataDoc = target[DataSym];
+        target[key] = acl;
+        if (dataDoc) dataDoc[key] = acl;
+        // dataDoc[key] = target[key] = acl;
+        // next line distributes the acl to all children of the target
+        DocListCast(dataDoc[Doc.LayoutFieldKey(dataDoc)]).map(d => {
+            if (d.author === Doc.CurrentUserEmail) {
+                this.distributeAcls(key, acl, d);
+                d[key] = acl;
+            }
+            const data = d[DataSym];
+            if (data && data.author === Doc.CurrentUserEmail) {
+                this.distributeAcls(key, acl, data);
+                data[key] = acl;
+            }
+        });
+
+        DocListCast(dataDoc[Doc.LayoutFieldKey(dataDoc) + "-annotations"]).map(d => {
+            if (d.author === Doc.CurrentUserEmail) {
+                this.distributeAcls(key, acl, d);
+                d[key] = acl;
+            }
+            const data = d[DataSym];
+            if (data && data.author === Doc.CurrentUserEmail) {
+                this.distributeAcls(key, acl, data);
+                data[key] = acl;
+            }
+            console.log(d, d[DataSym]);
+        });
 
     }
 
@@ -308,9 +348,9 @@ export default class SharingManager extends React.Component<{}> {
         const groupList = GroupManager.Instance?.getAllGroups() || [];
 
         const sortedUsers = this.users.sort(this.sortUsers)
-            .map(({ user: { email } }) => ({ label: email, value: "!indType/" + email }));
+            .map(({ user: { email } }) => ({ label: email, value: indType + email }));
         const sortedGroups = groupList.sort(this.sortGroups)
-            .map(({ groupName }) => ({ label: StrCast(groupName), value: "!groupType/" + StrCast(groupName) }));
+            .map(({ groupName }) => ({ label: StrCast(groupName), value: groupType + StrCast(groupName) }));
 
         const options: GroupOptions[] = GroupManager.Instance ?
             [
diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index eb58d8a3e..8740d17c2 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -1,4 +1,4 @@
-import { Doc, Opt, DataSym, DocListCast, AclReadonly, AclAddonly } from '../../fields/Doc';
+import { Doc, Opt, DataSym, DocListCast, AclReadonly, AclAddonly, AclPrivate, AclEdit, AclSym } from '../../fields/Doc';
 import { Touchable } from './Touchable';
 import { computed, action, observable } from 'mobx';
 import { Cast, BoolCast, ScriptCast } from '../../fields/Types';
@@ -7,7 +7,8 @@ import { InteractionUtils } from '../util/InteractionUtils';
 import { List } from '../../fields/List';
 import { DateField } from '../../fields/DateField';
 import { ScriptField } from '../../fields/ScriptField';
-import { GetEffectiveAcl } from '../../fields/util';
+import { GetEffectiveAcl, getPlaygroundMode } from '../../fields/util';
+import { SharingPermissions } from '../util/SharingManager';
 
 
 ///  DocComponent returns a generic React base class used by views that don't have 'fieldKey' props (e.g.,CollectionFreeFormDocumentView, DocumentView)
@@ -92,6 +93,13 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps, T
         // key where data is stored
         @computed get fieldKey() { return this.props.fieldKey; }
 
+        private AclMap = new Map<symbol, string>([
+            [AclPrivate, SharingPermissions.None],
+            [AclReadonly, SharingPermissions.View],
+            [AclAddonly, SharingPermissions.Add],
+            [AclEdit, SharingPermissions.Edit]
+        ]);
+
         lookupField = (field: string) => ScriptCast((this.layoutDoc as any).lookupField)?.script.run({ self: this.layoutDoc, data: this.rootDoc, field: field }).result;
 
         styleFromLayoutString = (scale: number) => {
@@ -139,11 +147,21 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps, T
             const docList = DocListCast(targetDataDoc[this.annotationKey]);
             const added = docs.filter(d => !docList.includes(d));
             const effectiveAcl = GetEffectiveAcl(this.dataDoc);
+
+            if (this.props.Document[AclSym]) {
+                added.forEach(d => {
+                    const dataDoc = d[DataSym];
+                    dataDoc[AclSym] = d[AclSym] = this.props.Document[AclSym];
+                    for (const [key, value] of Object.entries(this.props.Document[AclSym])) {
+                        dataDoc[key] = d[key] = this.AclMap.get(value);
+                    }
+                });
+            }
             if (added.length) {
-                if (effectiveAcl === AclReadonly) {
+                if (effectiveAcl === AclReadonly && !getPlaygroundMode()) {
                     return false;
                 } else if (effectiveAcl === AclAddonly) {
-                    added.map(doc => Doc.AddDocToList(targetDataDoc, this.annotationKey, doc));
+                    added.map(doc => console.log(Doc.AddDocToList(targetDataDoc, this.annotationKey, doc)));
                 } else {
                     added.map(doc => doc.context = this.props.Document);
                     targetDataDoc[this.annotationKey] = new List<Doc>([...docList, ...added]);
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 5c6781f4c..61d2246db 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -91,7 +91,7 @@ export class MainView extends React.Component {
     public isPointerDown = false;
 
     componentDidMount() {
-        DocServer.setPlaygroundFields(["dataTransition", "_viewTransition", "_panX", "_panY", "_viewScale", "_viewType", "_chromeStatus"]); // can play with these fields on someone else's
+        DocServer.setPlaygroundFields(["dataTransition", "_viewTransition", "_panX", "_panY", "_viewScale", "_viewType", "_chromeStatus", "data-annotations"]); // can play with these fields on someone else's
 
         const tag = document.createElement('script');
 
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 50d66c567..17567ea73 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -8,7 +8,7 @@ import * as React from 'react';
 import Lightbox from 'react-image-lightbox-with-rotate';
 import 'react-image-lightbox-with-rotate/style.css'; // This only needs to be imported once in your app
 import { DateField } from '../../../fields/DateField';
-import { AclAddonly, AclReadonly, DataSym, Doc, DocListCast, Field, Opt, AclEdit } from '../../../fields/Doc';
+import { AclAddonly, AclReadonly, DataSym, Doc, DocListCast, Field, Opt, AclEdit, AclSym, AclPrivate } from '../../../fields/Doc';
 import { Id } from '../../../fields/FieldSymbols';
 import { List } from '../../../fields/List';
 import { ObjectField } from '../../../fields/ObjectField';
@@ -48,6 +48,7 @@ import { CollectionTimeView } from './CollectionTimeView';
 import { CollectionTreeView } from "./CollectionTreeView";
 import './CollectionView.scss';
 import CollectionMenu from './CollectionMenu';
+import { SharingPermissions } from '../../util/SharingManager';
 const higflyout = require("@hig/flyout");
 export const { anchorPoints } = higflyout;
 export const Flyout = higflyout.default;
@@ -106,6 +107,13 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
 
     protected multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer;
 
+    private AclMap = new Map<symbol, string>([
+        [AclPrivate, SharingPermissions.None],
+        [AclReadonly, SharingPermissions.View],
+        [AclAddonly, SharingPermissions.Add],
+        [AclEdit, SharingPermissions.Edit]
+    ]);
+
     get collectionViewType(): CollectionViewType | undefined {
         const viewField = StrCast(this.props.Document._viewType);
         if (CollectionView._safeMode) {
@@ -128,11 +136,26 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
         if (this.props.filterAddDocument?.(doc) === false) {
             return false;
         }
+
         const docs = doc instanceof Doc ? [doc] : doc;
         const targetDataDoc = this.props.Document[DataSym];
         const docList = DocListCast(targetDataDoc[this.props.fieldKey]);
         const added = docs.filter(d => !docList.includes(d));
         const effectiveAcl = GetEffectiveAcl(this.props.Document);
+        if (this.props.Document[AclSym]) {
+            // change so it only adds if more restrictive
+            added.forEach(d => {
+                console.log(d[Id]);
+                const dataDoc = d[DataSym];
+                console.log(dataDoc[Id]);
+                for (const [key, value] of Object.entries(this.props.Document[AclSym])) {
+                    dataDoc[key] = d[key] = this.AclMap.get(value);
+                }
+                dataDoc[AclSym] = d[AclSym] = this.props.Document[AclSym];
+
+            });
+        }
+
         if (added.length) {
             if (effectiveAcl === AclReadonly && !getPlaygroundMode()) {
                 return false;
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index 5dfc14a4a..ef57171bf 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -109,15 +109,15 @@ const AclMap = new Map<string, symbol>([
 ]);
 
 export function fetchProto(doc: Doc) {
-    if (doc.author !== Doc.CurrentUserEmail) {
-        untracked(() => {
-            const permissions: { [key: string]: symbol } = {};
+    // if (doc.author !== Doc.CurrentUserEmail) {
+    untracked(() => {
+        const permissions: { [key: string]: symbol } = {};
 
-            Object.keys(doc).filter(key => key.startsWith("ACL")).forEach(key => permissions[key] = AclMap.get(StrCast(doc[key]))!);
+        Object.keys(doc).filter(key => key.startsWith("ACL")).forEach(key => permissions[key] = AclMap.get(StrCast(doc[key]))!);
 
-            if (Object.keys(permissions).length) doc[AclSym] = permissions;
-        });
-    }
+        if (Object.keys(permissions).length) doc[AclSym] = permissions;
+    });
+    // }
 
     if (doc.proto instanceof Promise) {
         doc.proto.then(fetchProto);
diff --git a/src/fields/util.ts b/src/fields/util.ts
index 6d2d715bd..ee01f6213 100644
--- a/src/fields/util.ts
+++ b/src/fields/util.ts
@@ -129,28 +129,31 @@ export function setGroups(groups: string[]) {
 export function GetEffectiveAcl(target: any, in_prop?: string | symbol | number): symbol {
     if (in_prop === UpdatingFromServer || target[UpdatingFromServer]) return AclEdit;
 
-    const HierarchyMapping = new Map<symbol, number>([
-        [AclPrivate, 0],
-        [AclReadonly, 1],
-        [AclAddonly, 2],
-        [AclEdit, 3]
-    ]);
-
     if (!target[AclSym] && target instanceof Doc) {
         fetchProto(target);
     }
 
+
     if (target[AclSym] && Object.keys(target[AclSym]).length) {
 
-        if (target.author === Doc.CurrentUserEmail || currentUserGroups.includes("admin")) return AclEdit;
+        // console.log(target[AclSym]);
+
+        if (target.__fields?.author === Doc.CurrentUserEmail || target.author === Doc.CurrentUserEmail || currentUserGroups.includes("admin")) return AclEdit;
 
         if (_overrideAcl || (in_prop && DocServer.PlaygroundFields?.includes(in_prop.toString()))) return AclEdit;
 
-        if (target[AclSym].ACL) return target[AclSym].ACL;
+        // if (target[AclSym].ACL) return target[AclSym].ACL;
 
         let effectiveAcl = AclPrivate;
         let aclPresent = false;
 
+        const HierarchyMapping = new Map<symbol, number>([
+            [AclPrivate, 0],
+            [AclReadonly, 1],
+            [AclAddonly, 2],
+            [AclEdit, 3]
+        ]);
+
         for (const [key, value] of Object.entries(target[AclSym])) {
             if (currentUserGroups.includes(key.substring(4)) || Doc.CurrentUserEmail === key.substring(4).replace("_", ".")) {
                 if (HierarchyMapping.get(value as symbol)! >= HierarchyMapping.get(effectiveAcl)!) {
-- 
cgit v1.2.3-70-g09d2


From fa68e59c31c9ad4b4458933a246440807529794b Mon Sep 17 00:00:00 2001
From: usodhi <61431818+usodhi@users.noreply.github.com>
Date: Tue, 21 Jul 2020 12:15:39 +0530
Subject: more addonly fixes

---
 src/client/documents/Documents.ts                  |  3 +++
 src/client/views/DocComponent.tsx                  | 10 ++++++----
 src/client/views/MainView.tsx                      |  2 +-
 src/client/views/collections/CollectionSubView.tsx |  6 ++++++
 4 files changed, 16 insertions(+), 5 deletions(-)

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 8e7d125b0..c783a761a 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -549,6 +549,9 @@ export namespace Docs {
             const dataDoc = MakeDataDelegate(proto, protoProps, data, fieldKey);
             const viewDoc = Doc.MakeDelegate(dataDoc, delegId);
 
+            // so that the list of annotations is already initialised, prevents issues in addonly
+            dataDoc[fieldKey + "-annotations"] = new List<Doc>();
+
             proto.links = ComputedField.MakeFunction("links(self)");
 
             viewDoc.author = Doc.CurrentUserEmail;
diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index 8740d17c2..2519360da 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -1,4 +1,4 @@
-import { Doc, Opt, DataSym, DocListCast, AclReadonly, AclAddonly, AclPrivate, AclEdit, AclSym } from '../../fields/Doc';
+import { Doc, Opt, DataSym, AclReadonly, AclAddonly, AclPrivate, AclEdit, AclSym, DocListCastAsync, DocListCast } from '../../fields/Doc';
 import { Touchable } from './Touchable';
 import { computed, action, observable } from 'mobx';
 import { Cast, BoolCast, ScriptCast } from '../../fields/Types';
@@ -126,11 +126,13 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps, T
             docs.map(doc => doc.annotationOn = undefined);
             const targetDataDoc = this.dataDoc;
             const value = DocListCast(targetDataDoc[this.annotationKey]);
-            const result = value.filter(v => !docs.includes(v));
-            if (result.length !== value.length) {
-                targetDataDoc[this.annotationKey] = new List<Doc>(result);
+            const toRemove = value.filter(v => docs.includes(v));
+            // can't assign new List<Doc>(result) to this because you can't assign new values in addonly
+            if (toRemove.length !== 0) {
+                toRemove.forEach(doc => Doc.RemoveDocFromList(targetDataDoc, this.annotationKey, doc));
                 return true;
             }
+
             return false;
         }
         // if the moved document is already in this overlay collection nothing needs to be done.
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 7184e8225..aadfdef21 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -90,7 +90,7 @@ export class MainView extends React.Component {
     public isPointerDown = false;
 
     componentDidMount() {
-        DocServer.setPlaygroundFields(["dataTransition", "_viewTransition", "_panX", "_panY", "_viewScale", "_viewType", "_chromeStatus", "data-annotations"]); // can play with these fields on someone else's
+        DocServer.setPlaygroundFields(["dataTransition", "_viewTransition", "_panX", "_panY", "_viewScale", "_viewType", "_chromeStatus"]); // can play with these fields on someone else's
 
         const tag = document.createElement('script');
 
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 3794088d4..8a3c2144e 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -91,6 +91,11 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
         // to its children which may be templates.
         // If 'annotationField' is specified, then all children exist on that field of the extension document, otherwise, they exist directly on the data document under 'fieldKey'
         @computed get dataField() {
+            // sets the dataDoc's data field to an empty list if the data field is undefined - prevents issues with addonly
+            // setTimeout changes it outside of the @computed section
+            setTimeout(() => {
+                if (!this.dataDoc[this.props.annotationsKey || this.props.fieldKey]) this.dataDoc[this.props.annotationsKey || this.props.fieldKey] = new List<Doc>();
+            }, 1000);
             return this.dataDoc[this.props.annotationsKey || this.props.fieldKey];
         }
 
@@ -418,4 +423,5 @@ import { FormattedTextBox, GoogleRef } from "../nodes/formattedText/FormattedTex
 import { CollectionView } from "./CollectionView";
 import { SelectionManager } from "../../util/SelectionManager";
 import { OverlayView } from "../OverlayView";
+import { setTimeout } from "timers";
 
-- 
cgit v1.2.3-70-g09d2

