From c42f909188aff5398de31e443500eb64b8690ac4 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 26 Aug 2021 08:57:20 -0400
Subject: fixed warnings/errors

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

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

diff --git a/src/client/views/nodes/LinkBox.tsx b/src/client/views/nodes/LinkBox.tsx
index c65ba9c69..55ea45bb8 100644
--- a/src/client/views/nodes/LinkBox.tsx
+++ b/src/client/views/nodes/LinkBox.tsx
@@ -30,6 +30,7 @@ export class LinkBox extends ViewBoxBaseComponent<FieldViewProps, LinkDocument>(
                 dontRegisterView={true}
                 renderDepth={this.props.renderDepth + 1}
                 CollectionView={undefined}
+                isAnyChildContentActive={returnFalse}
                 isContentActive={this.isContentActiveFunc}
                 addDocument={returnFalse}
                 removeDocument={returnFalse}
-- 
cgit v1.2.3-70-g09d2


From f097eefd91614d4efa2a89b3d8c7d1071d6c0b6f Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Fri, 17 Sep 2021 14:07:09 -0400
Subject: added 'unset' docFilters.  changed link doc views to use comparison
 box with title/caption.  fixed linkEditor to write to data doc. generalized
 comparisonBox rendering to use parameterized fields. fixed pdf/web to honor
 pointerEvents none prop and fixed textAnnotations to get rendered once as an
 Annotation. moved filterIcon stuff into DocumentView

---
 src/Utils.ts                                          |  4 +++-
 src/client/DocServer.ts                               |  2 ++
 src/client/documents/Documents.ts                     | 17 +++++++++++------
 src/client/views/collections/CollectionView.tsx       | 12 ------------
 .../collectionFreeForm/CollectionFreeFormLinkView.tsx |  6 +++---
 src/client/views/linking/LinkEditor.tsx               | 11 ++++++-----
 src/client/views/nodes/ComparisonBox.tsx              |  8 +++++---
 src/client/views/nodes/DocumentView.tsx               | 19 +++++++++++++++++--
 src/client/views/nodes/LinkBox.tsx                    | 19 ++++++-------------
 src/client/views/nodes/LinkDescriptionPopup.tsx       |  7 ++++---
 src/client/views/nodes/PDFBox.tsx                     |  9 ++++-----
 src/client/views/nodes/WebBox.tsx                     | 14 ++++++++------
 src/client/views/pdf/Annotation.scss                  |  3 +++
 src/client/views/pdf/PDFViewer.tsx                    | 13 +++++++------
 src/fields/Doc.ts                                     |  2 +-
 15 files changed, 80 insertions(+), 66 deletions(-)

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

diff --git a/src/Utils.ts b/src/Utils.ts
index 6eacd8296..e11f1154e 100644
--- a/src/Utils.ts
+++ b/src/Utils.ts
@@ -125,7 +125,9 @@ export namespace Utils {
         // bcz: isTransparent(__value__) is a hack.  it would be nice to have acual functions be parsed, but now Doc.matchFieldValue is hardwired to recognize just this one
         return `backgroundColor:${isTransparentFunctionHack},${noRecursionHack}:x`;// bcz: hack.  noRecursion should probably be either another ':' delimited field, or it should be a modifier to the comparision (eg., check, x, etc) field
     }
-
+    export function PropUnsetFilter(prop: string) {
+        return `${prop}:any,${noRecursionHack}:unset`;
+    }
 
     export function toRGBAstr(col: { r: number, g: number, b: number, a?: number }) {
         return "rgba(" + col.r + "," + col.g + "," + col.b + (col.a !== undefined ? "," + col.a : "") + ")";
diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts
index e498a7cca..3b376a0e7 100644
--- a/src/client/DocServer.ts
+++ b/src/client/DocServer.ts
@@ -241,6 +241,7 @@ export namespace DocServer {
             // the field has been returned from the server
             const getSerializedField = Utils.EmitCallback(_socket, MessageStore.GetRefField, id);
 
+            console.log(id)
             // when the serialized RefField has been received, go head and begin deserializing it into an object.
             // Here, once deserialized, we also invoke .proto to 'load' the document's prototype, which ensures that all
             // future .proto calls on the Doc won't have to go farther than the cache to get their actual value.
@@ -264,6 +265,7 @@ export namespace DocServer {
                 } else {
                     delete _cache[id];
                 }
+                console.log(id, field);
                 return field;
                 // either way, overwrite or delete any promises cached at this id (that we inserted as flags
                 // to indicate that the field was in the process of being fetched). Now everything
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index f50f306a3..e8185400e 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -962,13 +962,17 @@ export namespace DocUtils {
                 // metadata facets that exist
                 const exists = Object.keys(facet).filter(value => facet[value] === "exists");
 
+                // metadata facets that exist
+                const unsets = Object.keys(facet).filter(value => facet[value] === "unset");
+
                 // facets that have an x next to them
                 const xs = Object.keys(facet).filter(value => facet[value] === "x");
 
-                if (!exists.length && !xs.length && !checks.length && !matches.length) return true;
+                if (!unsets.length && !exists.length && !xs.length && !checks.length && !matches.length) return true;
                 const failsNotEqualFacets = !xs.length ? false : xs.some(value => Doc.matchFieldValue(d, facetKey, value));
                 const satisfiesCheckFacets = !checks.length ? true : checks.some(value => Doc.matchFieldValue(d, facetKey, value));
                 const satisfiesExistsFacets = !exists.length ? true : exists.some(value => d[facetKey] !== undefined);
+                const satisfiesUnsetsFacets = !unsets.length ? true : unsets.some(value => d[facetKey] === undefined);
                 const satisfiesMatchFacets = !matches.length ? true : matches.some(value => {
                     if (facetKey.startsWith("*")) { //  fields starting with a '*' are used to match families of related fields.  ie, *lastModified will match text-lastModified, data-lastModified, etc
                         const allKeys = Array.from(Object.keys(d));
@@ -980,11 +984,11 @@ export namespace DocUtils {
                 });
                 // if we're ORing them together, the default return is false, and we return true for a doc if it satisfies any one set of criteria
                 if ((parentCollection?.currentFilter as Doc)?.filterBoolean === "OR") {
-                    if (satisfiesExistsFacets && satisfiesCheckFacets && !failsNotEqualFacets && satisfiesMatchFacets) return true;
+                    if (satisfiesUnsetsFacets && satisfiesExistsFacets && satisfiesCheckFacets && !failsNotEqualFacets && satisfiesMatchFacets) return true;
                 }
                 // if we're ANDing them together, the default return is true, and we return false for a doc if it doesn't satisfy any set of criteria
                 else {
-                    if (!satisfiesExistsFacets || !satisfiesCheckFacets || failsNotEqualFacets || (matches.length && !satisfiesMatchFacets)) return false;
+                    if (!satisfiesUnsetsFacets || !satisfiesExistsFacets || !satisfiesCheckFacets || failsNotEqualFacets || (matches.length && !satisfiesMatchFacets)) return false;
                 }
 
             }
@@ -1088,10 +1092,11 @@ export namespace DocUtils {
             "anchor2-useLinkSmallAnchor": target.doc.useLinkSmallAnchor ? true : undefined,
             "acl-Public": SharingPermissions.Augment,
             "_acl-Public": SharingPermissions.Augment,
-            layout_linkView: Cast(Cast(Doc.UserDoc()["template-button-link"], Doc, null).dragFactory, Doc, null),
-            linkDisplay: true, hidden: true,
+            linkDisplay: true,
+            hidden: true,
             linkRelationship,
-            _layoutKey: "layout_linkView",
+            _showCaption: "description",
+            _showTitle: "linkRelationship",
             description
         }, id), showPopup);
     }
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 5c9c8063b..38e027fb3 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -246,12 +246,6 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
     childLayoutTemplate = () => this.props.childLayoutTemplate?.() || Cast(this.rootDoc.childLayoutTemplate, Doc, null);
     @computed get childLayoutString() { return StrCast(this.rootDoc.childLayoutString); }
 
-    /**
-    * Shows the filter icon if it's a user-created collection which isn't a dashboard and has some docFilters applied on it or on the current dashboard.
-    */
-    @computed get showFilterIcon() {
-        return this.props.Document.viewType !== CollectionViewType.Docking && !Doc.IsSystem(this.props.Document) && this._subView?.IsFiltered();
-    }
 
     @observable _subView: any = undefined;
 
@@ -280,12 +274,6 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
             style={{ pointerEvents: this.props.layerProvider?.(this.rootDoc) === false ? "none" : undefined }}>
             {this.showIsTagged()}
             {this.collectionViewType !== undefined ? this.SubView(this.collectionViewType, props) : (null)}
-            {this.showFilterIcon ?
-                <FontAwesomeIcon icon={"filter"} size="lg"
-                    style={{ position: 'absolute', top: '1%', right: '1%', cursor: "pointer", padding: 1, color: this.showFilterIcon === "hasFilter" ? '#18c718bd' : "orange", zIndex: 1 }}
-                    onPointerDown={action(e => { this.props.select(false); CurrentUserUtils.propertiesWidth = 250; e.stopPropagation(); })}
-                />
-                : (null)}
         </div>);
     }
 }
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
index 3b3e069d8..2cb487588 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
@@ -1,6 +1,6 @@
 import { action, computed, IReactionDisposer, observable, reaction } from "mobx";
 import { observer } from "mobx-react";
-import { Doc } from "../../../../fields/Doc";
+import { Doc, Field } from "../../../../fields/Doc";
 import { Id } from "../../../../fields/FieldSymbols";
 import { List } from "../../../../fields/List";
 import { NumCast, StrCast } from "../../../../fields/Types";
@@ -180,7 +180,7 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
         if (!this.renderData) return (null);
         const { a, b, pt1norm, pt2norm, aActive, bActive, textX, textY, pt1, pt2 } = this.renderData;
         LinkManager.currentLink = this.props.LinkDocs[0];
-        const linkRelationship = StrCast(LinkManager.currentLink?.linkRelationship); //get string representing relationship
+        const linkRelationship = Field.toString(LinkManager.currentLink?.linkRelationship as any as Field); //get string representing relationship
         const linkRelationshipList = Doc.UserDoc().linkRelationshipList as List<string>;
         const linkColorList = Doc.UserDoc().linkColorList as List<string>;
         //access stroke color using index of the relationship in the color list (default black)
@@ -189,7 +189,7 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
             <path className="collectionfreeformlinkview-linkLine" style={{ opacity: this._opacity, strokeDasharray: "2 2", stroke: strokeColor }}
                 d={`M ${pt1[0]} ${pt1[1]} C ${pt1[0] + pt1norm[0]} ${pt1[1] + pt1norm[1]}, ${pt2[0] + pt2norm[0]} ${pt2[1] + pt2norm[1]}, ${pt2[0]} ${pt2[1]}`} />
             {textX === undefined ? (null) : <text className="collectionfreeformlinkview-linkText" x={textX} y={textY} onPointerDown={this.pointerDown} >
-                {StrCast(this.props.LinkDocs[0].description)}
+                {Field.toString(this.props.LinkDocs[0].description as any as Field)}
             </text>}
         </>);
     }
diff --git a/src/client/views/linking/LinkEditor.tsx b/src/client/views/linking/LinkEditor.tsx
index 240a71c3e..219f7d3a2 100644
--- a/src/client/views/linking/LinkEditor.tsx
+++ b/src/client/views/linking/LinkEditor.tsx
@@ -2,13 +2,14 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
 import { Tooltip } from "@material-ui/core";
 import { action, computed, observable } from "mobx";
 import { observer } from "mobx-react";
-import { Doc, StrListCast } from "../../../fields/Doc";
-import { DateCast, StrCast } from "../../../fields/Types";
+import { Doc, StrListCast, Field } from "../../../fields/Doc";
+import { DateCast, StrCast, Cast } from "../../../fields/Types";
 import { LinkManager } from "../../util/LinkManager";
 import { undoBatch } from "../../util/UndoManager";
 import './LinkEditor.scss';
 import { LinkRelationshipSearch } from "./LinkRelationshipSearch";
 import React = require("react");
+import { ToString } from "../../../fields/FieldSymbols";
 
 
 interface LinkEditorProps {
@@ -20,7 +21,7 @@ interface LinkEditorProps {
 @observer
 export class LinkEditor extends React.Component<LinkEditorProps> {
 
-    @observable description = StrCast(LinkManager.currentLink?.description);
+    @observable description = Field.toString(LinkManager.currentLink?.description as any as Field);
     @observable relationship = StrCast(LinkManager.currentLink?.linkRelationship);
     @observable openDropdown: boolean = false;
     @observable showInfo: boolean = false;
@@ -41,7 +42,7 @@ export class LinkEditor extends React.Component<LinkEditorProps> {
     @undoBatch
     setRelationshipValue = action((value: string) => {
         if (LinkManager.currentLink) {
-            LinkManager.currentLink.linkRelationship = value;
+            Doc.GetProto(LinkManager.currentLink).linkRelationship = value;
             const linkRelationshipList = StrListCast(Doc.UserDoc().linkRelationshipList);
             const linkColorList = StrListCast(Doc.UserDoc().linkColorList);
             // if the relationship does not exist in the list, add it and a corresponding unique randomly generated color 
@@ -79,7 +80,7 @@ export class LinkEditor extends React.Component<LinkEditorProps> {
     @undoBatch
     setDescripValue = action((value: string) => {
         if (LinkManager.currentLink) {
-            LinkManager.currentLink.description = value;
+            Doc.GetProto(LinkManager.currentLink).description = value;
             this.buttonColor = "rgb(62, 133, 55)";
             setTimeout(action(() => this.buttonColor = ""), 750);
             return true;
diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx
index 6708a08ee..72c7e4f45 100644
--- a/src/client/views/nodes/ComparisonBox.tsx
+++ b/src/client/views/nodes/ComparisonBox.tsx
@@ -15,6 +15,7 @@ import "./ComparisonBox.scss";
 import { DocumentView, DocumentViewProps } from './DocumentView';
 import { FieldView, FieldViewProps } from './FieldView';
 import React = require("react");
+import { DocumentType } from '../../documents/DocumentTypes';
 
 export const comparisonSchema = createSchema({});
 
@@ -87,7 +88,8 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
             </div>;
         };
         const displayDoc = (which: string) => {
-            const whichDoc = Cast(this.dataDoc[`compareBox-${which}`], Doc, null);
+            var whichDoc = Cast(this.dataDoc[which], Doc, null);
+            if (whichDoc.type === DocumentType.MARKER) whichDoc = Cast(whichDoc.annotationOn, Doc, null);
             return whichDoc ? <>
                 <DocumentView {...OmitKeys(this.props, ["NativeWidth", "NativeHeight"]).omit}
                     isContentActive={returnFalse}
@@ -112,9 +114,9 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
 
         return (
             <div className={`comparisonBox${this.props.isContentActive() || SnappingManager.GetIsDragging() ? "-interactive" : ""}` /* change className to easily disable/enable pointer events in CSS */}>
-                {displayBox("after", 1, this.props.PanelWidth() - 3)}
+                {displayBox(this.fieldKey === "data" ? "compareBox-after" : `${this.fieldKey}2`, 1, this.props.PanelWidth() - 3)}
                 <div className="clip-div" style={{ width: clipWidth, transition: this._animating, background: StrCast(this.layoutDoc._backgroundColor, "gray") }}>
-                    {displayBox("before", 0, 0)}
+                    {displayBox(this.fieldKey === "data" ? "compareBox-before" : `${this.fieldKey}1`, 0, 0)}
                 </div>
 
                 <div className="slide-bar" style={{ left: `calc(${clipWidth} - 0.5px)`, cursor: NumCast(this.layoutDoc._clipWidth) < 5 ? "e-resize" : NumCast(this.layoutDoc._clipWidth) / 100 > (this.props.PanelWidth() - 5) / this.props.PanelWidth() ? "w-resize" : undefined }}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 46a8b6629..35249c7f4 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -13,7 +13,7 @@ import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from "../../../fields/Ty
 import { AudioField } from "../../../fields/URLField";
 import { GetEffectiveAcl, SharingPermissions, TraceMobx } from '../../../fields/util';
 import { MobileInterface } from '../../../mobile/MobileInterface';
-import { emptyFunction, hasDescendantTarget, OmitKeys, returnTrue, returnVal, Utils, lightOrDark, simulateMouseClick } from "../../../Utils";
+import { emptyFunction, hasDescendantTarget, OmitKeys, returnTrue, returnVal, Utils, lightOrDark, simulateMouseClick, returnEmptyString } from "../../../Utils";
 import { GooglePhotos } from '../../apis/google_docs/GooglePhotosClientUtils';
 import { Docs, DocUtils } from "../../documents/Documents";
 import { DocumentType } from '../../documents/DocumentTypes';
@@ -802,6 +802,12 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
         cm.displayMenu((e?.pageX || pageX || 0) - 15, (e?.pageY || pageY || 0) - 15);
     }
 
+    collectionFilters = () => StrListCast(this.props.Document._docFilters);
+    collectionRangeDocFilters = () => StrListCast(this.props.Document._docRangeFilters);
+    @computed get showFilterIcon() {
+        return this.collectionFilters().length || this.collectionRangeDocFilters().length ? "hasFilter" :
+            this.props.docFilters?.().filter(f => Utils.IsRecursiveFilter(f)).length || this.props.docRangeFilters().length ? "inheritsFilter" : undefined
+    }
     rootSelected = (outsideReaction?: boolean) => this.props.isSelected(outsideReaction) || (this.props.Document.rootDocument && this.props.rootSelected?.(outsideReaction)) || false;
     panelHeight = () => this.props.PanelHeight() - this.headerMargin;
     screenToLocal = () => this.props.ScreenToLocalTransform().translate(0, -this.headerMargin);
@@ -832,7 +838,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
             </div>;
         return <div className="documentView-contentsView"
             style={{
-                pointerEvents: this.rootDoc.type !== DocumentType.INK && ((this.props.contentPointerEvents as any) || (this.isContentActive())) ? "all" : "none",
+                pointerEvents: this.props.pointerEvents as any ? this.props.pointerEvents as any : (this.rootDoc.type !== DocumentType.INK && ((this.props.contentPointerEvents as any) || (this.isContentActive())) ? "all" : "none"),
                 height: this.headerMargin ? `calc(100% - ${this.headerMargin}px)` : undefined,
             }}>
             <DocumentContentsView key={1} {...this.props}
@@ -869,6 +875,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
     anchorPanelHeight = () => this.props.PanelHeight() || 1;
     anchorStyleProvider = (doc: Opt<Doc>, props: Opt<DocumentViewProps>, property: string): any => {
         switch (property) {
+            case StyleProp.ShowTitle: return "";
             case StyleProp.PointerEvents: return "none";
             case StyleProp.LinkSource: return this.props.Document;// pass the LinkSource to the LinkAnchorBox
             default: return this.props.styleProvider?.(doc, props, property);
@@ -901,6 +908,8 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                     PanelWidth={this.anchorPanelWidth}
                     PanelHeight={this.anchorPanelHeight}
                     dontRegisterView={false}
+                    showTitle={returnEmptyString}
+                    hideCaptions={true}
                     fitWidth={returnTrue}
                     styleProvider={this.anchorStyleProvider}
                     removeDocument={this.hideLinkAnchor}
@@ -1087,6 +1096,12 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                     </div>
                 </>
             }
+            {this.showFilterIcon ?
+                <FontAwesomeIcon icon={"filter"} size="lg"
+                    style={{ position: 'absolute', top: '1%', right: '1%', cursor: "pointer", padding: 1, color: this.showFilterIcon === "hasFilter" ? '#18c718bd' : "orange", zIndex: 1 }}
+                    onPointerDown={action(e => { this.props.select(false); CurrentUserUtils.propertiesWidth = 250; e.stopPropagation(); })}
+                />
+                : (null)}
         </div>;
     }
 }
diff --git a/src/client/views/nodes/LinkBox.tsx b/src/client/views/nodes/LinkBox.tsx
index 55ea45bb8..b82d16677 100644
--- a/src/client/views/nodes/LinkBox.tsx
+++ b/src/client/views/nodes/LinkBox.tsx
@@ -2,10 +2,10 @@ import React = require("react");
 import { observer } from "mobx-react";
 import { documentSchema } from "../../../fields/documentSchemas";
 import { makeInterface } from "../../../fields/Schema";
-import { returnFalse } from "../../../Utils";
-import { CollectionTreeView } from "../collections/CollectionTreeView";
+import { emptyFunction, returnFalse } from "../../../Utils";
 import { ViewBoxBaseComponent } from "../DocComponent";
 import { StyleProp } from "../StyleProvider";
+import { ComparisonBox } from "./ComparisonBox";
 import { FieldView, FieldViewProps } from './FieldView';
 import "./LinkBox.scss";
 
@@ -20,22 +20,15 @@ export class LinkBox extends ViewBoxBaseComponent<FieldViewProps, LinkDocument>(
         if (this.dataDoc.treeViewOpen === undefined) setTimeout(() => this.dataDoc.treeViewOpen = true);
         return <div className={`linkBox-container${this.isContentActive() ? "-interactive" : ""}`}
             style={{ background: this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BackgroundColor) }} >
-            <CollectionTreeView {...this.props}
-                childDocuments={[this.dataDoc]}
-                treeViewOpen={true}
-                treeViewExpandedView={"fields"}
-                treeViewHideTitle={true}
-                treeViewSkipFields={["treeViewExpandedView", "aliases", "_removeDropProperties",
-                    "treeViewOpen", "aliasNumber", "isPrototype", "creationDate", "author"]}
+            <ComparisonBox {...this.props}
+                fieldKey="anchor"
+                setHeight={emptyFunction}
                 dontRegisterView={true}
                 renderDepth={this.props.renderDepth + 1}
-                CollectionView={undefined}
-                isAnyChildContentActive={returnFalse}
                 isContentActive={this.isContentActiveFunc}
                 addDocument={returnFalse}
                 removeDocument={returnFalse}
-                moveDocument={returnFalse}>
-            </CollectionTreeView>
+                moveDocument={returnFalse} />
         </div>;
     }
 } 
\ No newline at end of file
diff --git a/src/client/views/nodes/LinkDescriptionPopup.tsx b/src/client/views/nodes/LinkDescriptionPopup.tsx
index b62a4dd56..a9d33f161 100644
--- a/src/client/views/nodes/LinkDescriptionPopup.tsx
+++ b/src/client/views/nodes/LinkDescriptionPopup.tsx
@@ -1,8 +1,9 @@
 import React = require("react");
+import { action, observable } from "mobx";
 import { observer } from "mobx-react";
-import "./LinkDescriptionPopup.scss";
-import { observable, action } from "mobx";
+import { Doc } from "../../../fields/Doc";
 import { LinkManager } from "../../util/LinkManager";
+import "./LinkDescriptionPopup.scss";
 import { TaskCompletionBox } from "./TaskCompletedBox";
 
 
@@ -25,7 +26,7 @@ export class LinkDescriptionPopup extends React.Component<{}> {
     onDismiss = (add: boolean) => {
         LinkDescriptionPopup.descriptionPopup = false;
         if (add) {
-            LinkManager.currentLink && (LinkManager.currentLink.description = this.description);
+            LinkManager.currentLink && (Doc.GetProto(LinkManager.currentLink).description = this.description);
         }
     }
 
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index f0a502e31..30b4dc92a 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -3,9 +3,9 @@ import { action, computed, IReactionDisposer, observable, reaction, runInAction
 import { observer } from "mobx-react";
 import * as Pdfjs from "pdfjs-dist";
 import "pdfjs-dist/web/pdf_viewer.css";
-import { Doc, DocListCast, Opt, WidthSym } from "../../../fields/Doc";
+import { Doc, DocListCast, Opt, WidthSym, StrListCast } from "../../../fields/Doc";
 import { documentSchema } from '../../../fields/documentSchemas';
-import { makeInterface } from "../../../fields/Schema";
+import { makeInterface, listSpec } from "../../../fields/Schema";
 import { Cast, NumCast, StrCast } from '../../../fields/Types';
 import { PdfField } from "../../../fields/URLField";
 import { TraceMobx } from '../../../fields/util';
@@ -25,6 +25,7 @@ import { FieldView, FieldViewProps } from './FieldView';
 import { pageSchema } from "./ImageBox";
 import "./PDFBox.scss";
 import React = require("react");
+import { CurrentUserUtils } from '../../util/CurrentUserUtils';
 
 type PdfDocument = makeInterface<[typeof documentSchema, typeof panZoomSchema, typeof pageSchema]>;
 const PdfDocument = makeInterface(documentSchema, panZoomSchema, pageSchema);
@@ -249,9 +250,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     @observable _showSidebar = false;
     @computed get SidebarShown() { return this._showSidebar || this.layoutDoc._showSidebar ? true : false; }
 
-    contentScaling = () => {
-        return 1;
-    }
+    contentScaling = () => 1;
     @computed get renderPdfView() {
         TraceMobx();
         const previewScale = this._previewNativeWidth ? 1 - this.sidebarWidth() / this._previewNativeWidth : 1;
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index 6a20ca14a..60a83d612 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -532,7 +532,8 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
             NumCast(this.layoutDoc.nativeWidth)
 
     @computed get content() {
-        return <div className={"webBox-cont" + (!this.props.docViewPath().lastElement()?.docView?._pendingDoubleClick && this.props.isContentActive() && CurrentUserUtils.SelectedTool === InkTool.None && !DocumentDecorations.Instance?.Interacting ? "-interactive" : "")}
+        const interactive = !this.props.docViewPath().lastElement()?.docView?._pendingDoubleClick && this.props.isContentActive() && this.props.pointerEvents !== "none" && CurrentUserUtils.SelectedTool === InkTool.None && !DocumentDecorations.Instance?.Interacting;
+        return <div className={"webBox-cont" + (interactive ? "-interactive" : "")}
             style={{ width: !this.layoutDoc.allowReflow ? NumCast(this.layoutDoc[this.fieldKey + "-nativeWidth"]) || `100%` : "100%", }}>
             {this.urlContent}
         </div>;
@@ -575,10 +576,11 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     panelHeight = () => this.props.PanelHeight() / (this.props.scaling?.() || 1); // () => this._pageSizes.length && this._pageSizes[0] ? this._pageSizes[0].width : Doc.NativeWidth(this.Document);
     scrollXf = () => this.props.ScreenToLocalTransform().translate(0, NumCast(this.layoutDoc._scrollTop));
     anchorMenuClick = () => this._sidebarRef.current?.anchorMenuClick;
-    transparentFilter = () => [...this.props.docFilters(), Utils.IsTransparentFilter()];
-    opaqueFilter = () => [...this.props.docFilters(), Utils.IsOpaqueFilter()];
+    basicFilter = () => [...this.props.docFilters(), Utils.PropUnsetFilter("textInlineAnnotations")];
+    transparentFilter = () => [Utils.IsTransparentFilter(), ...this.basicFilter()];
+    opaqueFilter = () => [Utils.IsOpaqueFilter(), ...this.basicFilter()];
     render() {
-        const pointerEvents = this.props.layerProvider?.(this.layoutDoc) === false ? "none" : undefined;
+        const pointerEvents = this.props.layerProvider?.(this.layoutDoc) === false ? "none" : this.props.pointerEvents ? this.props.pointerEvents as any : undefined;
         const previewScale = this._previewNativeWidth ? 1 - this.sidebarWidth() / this._previewNativeWidth : 1;
         const scale = previewScale * (this.props.scaling?.() || 1);
         const renderAnnotations = (docFilters?: () => string[]) =>
@@ -593,7 +595,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                 ScreenToLocalTransform={this.scrollXf}
                 scaling={returnOne}
                 dropAction={"alias"}
-                docFilters={docFilters || this.props.docFilters}
+                docFilters={docFilters || this.basicFilter}
                 dontRenderDocuments={docFilters ? false : true}
                 select={emptyFunction}
                 ContentScaling={returnOne}
@@ -606,7 +608,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                 pointerEvents={CurrentUserUtils.SelectedTool !== InkTool.None || this._isAnnotating || SnappingManager.GetIsDragging() ? "all" : "none"} />;
         return (
             <div className="webBox" ref={this._mainCont}
-                style={{ pointerEvents: this.props.isContentActive() && !MarqueeOptionsMenu.Instance.isShown() ? "all" : SnappingManager.GetIsDragging() ? undefined : "none" }} >
+                style={{ pointerEvents: this.props.isContentActive() && this.props.pointerEvents !== "none" && !MarqueeOptionsMenu.Instance.isShown() ? "all" : SnappingManager.GetIsDragging() ? undefined : "none" }} >
                 <div className={`webBox-container`} style={{ pointerEvents }} onContextMenu={this.specificContextMenu}>
                     <base target="_blank" />
                     <div className={"webBox-outerContent"} ref={this._outerRef}
diff --git a/src/client/views/pdf/Annotation.scss b/src/client/views/pdf/Annotation.scss
index e98f071c3..1de60ffed 100644
--- a/src/client/views/pdf/Annotation.scss
+++ b/src/client/views/pdf/Annotation.scss
@@ -4,4 +4,7 @@
     position: absolute;
     background-color: rgba(146, 245, 95, 0.467);
     transition: opacity 0.5s;
+    &:hover {
+        cursor: pointer;
+    }
 }
\ No newline at end of file
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 7aa18e46f..78adedf5b 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -179,7 +179,7 @@ export class PDFViewer extends React.Component<IViewerProps> {
         let focusSpeed: Opt<number>;
         if (doc !== this.props.rootDoc && mainCont) {
             const windowHeight = this.props.PanelHeight() / (this.props.scaling?.() || 1);
-            const scrollTo = Utils.scrollIntoView(NumCast(doc.y), doc[HeightSym](), NumCast(this.props.layoutDoc._scrollTop), windowHeight, .1 * windowHeight);
+            const scrollTo = doc.unrendered ? NumCast(doc.y) : Utils.scrollIntoView(NumCast(doc.y), doc[HeightSym](), NumCast(this.props.layoutDoc._scrollTop), windowHeight, .1 * windowHeight);
             if (scrollTo !== undefined) {
                 focusSpeed = 500;
 
@@ -502,8 +502,9 @@ export class PDFViewer extends React.Component<IViewerProps> {
     overlayTransform = () => this.scrollXf().scale(1 / this._zoomed);
     panelWidth = () => this.props.PanelWidth() / (this.props.scaling?.() || 1); // (this.Document.scrollHeight || Doc.NativeHeight(this.Document) || 0);
     panelHeight = () => this.props.PanelHeight() / (this.props.scaling?.() || 1); // () => this._pageSizes.length && this._pageSizes[0] ? this._pageSizes[0].width : Doc.NativeWidth(this.Document);
-    transparentFilter = () => [...this.props.docFilters(), Utils.IsTransparentFilter()];
-    opaqueFilter = () => [...this.props.docFilters(), Utils.IsOpaqueFilter()];
+    basicFilter = () => [...this.props.docFilters(), Utils.PropUnsetFilter("textInlineAnnotations")];
+    transparentFilter = () => [Utils.IsTransparentFilter(), ...this.basicFilter()];
+    opaqueFilter = () => [Utils.IsOpaqueFilter(), ...this.basicFilter()];
     @computed get overlayLayer() {
         const renderAnnotations = (docFilters?: () => string[]) =>
             <CollectionFreeFormView {...OmitKeys(this.props, ["NativeWidth", "NativeHeight", "setContentView"]).omit}
@@ -516,7 +517,7 @@ export class PDFViewer extends React.Component<IViewerProps> {
                 select={emptyFunction}
                 ContentScaling={this.contentZoom}
                 bringToFront={emptyFunction}
-                docFilters={docFilters || this.props.docFilters}
+                docFilters={docFilters || this.basicFilter}
                 dontRenderDocuments={docFilters ? false : true}
                 CollectionView={undefined}
                 ScreenToLocalTransform={this.overlayTransform}
@@ -543,7 +544,7 @@ export class PDFViewer extends React.Component<IViewerProps> {
         </div>;
     }
     @computed get pdfViewerDiv() {
-        return <div className={"pdfViewerDash-text" + (this._textSelecting && (this.props.isSelected() || this.props.isContentActive()) ? "-selected" : "")} ref={this._viewer} />;
+        return <div className={"pdfViewerDash-text" + (this.props.pointerEvents !== "none" && this._textSelecting && (this.props.isSelected() || this.props.isContentActive()) ? "-selected" : "")} ref={this._viewer} />;
     }
     @computed get contentScaling() { return this.props.ContentScaling?.() || 1; }
     @computed get standinViews() {
@@ -556,7 +557,7 @@ export class PDFViewer extends React.Component<IViewerProps> {
     render() {
         TraceMobx();
         return <div className="pdfViewer-content">
-            <div className={`pdfViewerDash${this.props.isContentActive() ? "-interactive" : ""}`} ref={this._mainCont}
+            <div className={`pdfViewerDash${this.props.isContentActive() && this.props.pointerEvents !== "none" ? "-interactive" : ""}`} ref={this._mainCont}
                 onScroll={this.onScroll} onWheel={this.onZoomWheel} onPointerDown={this.onPointerDown} onClick={this.onClick}
                 style={{
                     overflowX: this._zoomed !== 1 ? "scroll" : undefined,
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index 4d040f3bc..57bd0f46f 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -1136,7 +1136,7 @@ export namespace Doc {
     // filters document in a container collection:
     // all documents with the specified value for the specified key are included/excluded
     // based on the modifiers :"check", "x", undefined
-    export function setDocFilter(container: Opt<Doc>, key: string, value: any, modifiers: "remove" | "match" | "check" | "x" | "exists", toggle?: boolean, fieldSuffix?: string, append: boolean = true) {
+    export function setDocFilter(container: Opt<Doc>, key: string, value: any, modifiers: "remove" | "match" | "check" | "x" | "exists" | "unset", toggle?: boolean, fieldSuffix?: string, append: boolean = true) {
         if (!container) return;
         const filterField = "_" + (fieldSuffix ? fieldSuffix + "-" : "") + "docFilters";
         const docFilters = Cast(container[filterField], listSpec("string"), []);
-- 
cgit v1.2.3-70-g09d2

