From bc59ea805f32568f0835bd55d39575236c24a066 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Thu, 21 Mar 2019 22:22:25 -0400
Subject: added very basic cycle detection when adding to collections

---
 src/client/views/collections/CollectionView.tsx | 22 ++++++++++++++++++----
 1 file changed, 18 insertions(+), 4 deletions(-)

(limited to 'src/client/views/collections/CollectionView.tsx')

diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 7e1d31018..2e93e6bb8 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -37,7 +37,7 @@ export class CollectionView extends React.Component<CollectionViewProps> {
     @observable
     public SelectedDocs: FieldId[] = [];
     public active: () => boolean = () => CollectionView.Active(this);
-    addDocument = (doc: Document, allowDuplicates: boolean): void => { CollectionView.AddDocument(this.props, doc, allowDuplicates); }
+    addDocument = (doc: Document, allowDuplicates: boolean): boolean => { return CollectionView.AddDocument(this.props, doc, allowDuplicates); }
     removeDocument = (doc: Document): boolean => { return CollectionView.RemoveDocument(this.props, doc); }
     get subView() { return CollectionView.SubView(this); }
 
@@ -48,17 +48,31 @@ export class CollectionView extends React.Component<CollectionViewProps> {
         return isSelected || childSelected || topMost;
     }
 
+    static createsCycle(doc: Document, props: CollectionViewProps): boolean {
+        let ldata = doc.GetList<Document>(KeyStore.Data, []);
+        for (let i = 0; i < ldata.length; i++) {
+            if (CollectionView.createsCycle(ldata[i], props))
+                return true;
+        }
+        return doc.Id == props.Document.Id;
+    }
+
     @action
-    public static AddDocument(props: CollectionViewProps, doc: Document, allowDuplicates: boolean) {
+    public static AddDocument(props: CollectionViewProps, doc: Document, allowDuplicates: boolean): boolean {
         doc.SetNumber(KeyStore.Page, props.Document.GetNumber(KeyStore.CurPage, -1));
         if (props.Document.Get(props.fieldKey) instanceof Field) {
             //TODO This won't create the field if it doesn't already exist
             const value = props.Document.GetData(props.fieldKey, ListField, new Array<Document>())
-            if (!value.some(v => v.Id == doc.Id) || allowDuplicates)
-                value.push(doc);
+            if (!CollectionView.createsCycle(doc, props)) {
+                if (!value.some(v => v.Id == doc.Id) || allowDuplicates)
+                    value.push(doc);
+            }
+            else
+                return false;
         } else {
             props.Document.SetOnPrototype(props.fieldKey, new ListField([doc]));
         }
+        return true;
     }
 
     @action
-- 
cgit v1.2.3-70-g09d2


From eb27dd447502ee1f55296b9e496aee998b0259f2 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Thu, 21 Mar 2019 23:10:42 -0400
Subject: avoided another cycle

---
 src/client/views/collections/CollectionView.tsx | 29 +++++++++++++++++++------
 1 file changed, 22 insertions(+), 7 deletions(-)

(limited to 'src/client/views/collections/CollectionView.tsx')

diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 2e93e6bb8..be757e22e 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -14,6 +14,7 @@ import { CollectionViewProps } from "./CollectionViewBase";
 import { CollectionTreeView } from "./CollectionTreeView";
 import { Field, FieldId, FieldWaiting } from "../../../fields/Field";
 import { Main } from "../Main";
+import { dropPoint } from "prosemirror-transform";
 
 export enum CollectionViewType {
     Invalid,
@@ -48,13 +49,22 @@ export class CollectionView extends React.Component<CollectionViewProps> {
         return isSelected || childSelected || topMost;
     }
 
-    static createsCycle(doc: Document, props: CollectionViewProps): boolean {
-        let ldata = doc.GetList<Document>(KeyStore.Data, []);
-        for (let i = 0; i < ldata.length; i++) {
-            if (CollectionView.createsCycle(ldata[i], props))
+    static createsCycle(documentToAdd: Document, containerDocument: Document): boolean {
+        let data = documentToAdd.GetList<Document>(KeyStore.Data, []);
+        for (let i = 0; i < data.length; i++) {
+            if (CollectionView.createsCycle(data[i], containerDocument))
                 return true;
         }
-        return doc.Id == props.Document.Id;
+        let annots = documentToAdd.GetList<Document>(KeyStore.Annotations, []);
+        for (let i = 0; i < annots.length; i++) {
+            if (CollectionView.createsCycle(annots[i], containerDocument))
+                return true;
+        }
+        for (let containerProto: any = containerDocument; containerProto && containerProto != FieldWaiting; containerProto = containerProto.GetPrototype()) {
+            if (containerProto.Id == documentToAdd.Id)
+                return true;
+        }
+        return false;
     }
 
     @action
@@ -63,14 +73,19 @@ export class CollectionView extends React.Component<CollectionViewProps> {
         if (props.Document.Get(props.fieldKey) instanceof Field) {
             //TODO This won't create the field if it doesn't already exist
             const value = props.Document.GetData(props.fieldKey, ListField, new Array<Document>())
-            if (!CollectionView.createsCycle(doc, props)) {
+            if (!CollectionView.createsCycle(doc, props.Document)) {
                 if (!value.some(v => v.Id == doc.Id) || allowDuplicates)
                     value.push(doc);
             }
             else
                 return false;
         } else {
-            props.Document.SetOnPrototype(props.fieldKey, new ListField([doc]));
+            let proto = props.Document.GetPrototype();
+            if (!proto || proto == FieldWaiting || !CollectionView.createsCycle(proto, doc)) {
+                props.Document.SetOnPrototype(props.fieldKey, new ListField([doc]));
+            }
+            else
+                return false;
         }
         return true;
     }
-- 
cgit v1.2.3-70-g09d2

