aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2023-11-07 13:48:26 -0500
committerbobzel <zzzman@gmail.com>2023-11-07 13:48:26 -0500
commita6cc25e5d03ffed16bfaa32e48e9cc2eaff7deaf (patch)
tree1322ef9a743457f23851ba7c9d5d3dd090f1f75d
parenta4e3b645317c4589cf49f8007f6e6b57cf2c12d3 (diff)
Changed how selection works to avoid invalidations. Fixed Cast problem with ProxyFields that caused renameEmbedding to infinite loop.. Changed brushing for the same reason. Cleaned up a few things with filter code.
-rw-r--r--src/Utils.ts24
-rw-r--r--src/client/documents/Documents.ts2
-rw-r--r--src/client/util/CurrentUserUtils.ts2
-rw-r--r--src/client/util/SelectionManager.ts59
-rw-r--r--src/client/views/DocComponent.tsx8
-rw-r--r--src/client/views/StyleProvider.tsx6
-rw-r--r--src/client/views/collections/CollectionMenu.tsx19
-rw-r--r--src/client/views/collections/CollectionSubView.tsx2
-rw-r--r--src/client/views/collections/TabDocView.tsx4
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx20
-rw-r--r--src/client/views/collections/collectionSchema/CollectionSchemaView.tsx12
-rw-r--r--src/client/views/nodes/DocumentView.tsx18
-rw-r--r--src/client/views/nodes/MapBox/MapBox.tsx4
-rw-r--r--src/client/views/nodes/MapBox/MapBox2.tsx4
-rw-r--r--src/client/views/nodes/WebBox.tsx4
-rw-r--r--src/client/views/pdf/Annotation.tsx2
-rw-r--r--src/client/views/pdf/PDFViewer.tsx12
-rw-r--r--src/fields/Doc.ts95
-rw-r--r--src/fields/DocSymbols.ts2
-rw-r--r--src/fields/Types.ts3
20 files changed, 119 insertions, 183 deletions
diff --git a/src/Utils.ts b/src/Utils.ts
index 330ca59f9..9499aaf2f 100644
--- a/src/Utils.ts
+++ b/src/Utils.ts
@@ -157,23 +157,19 @@ export namespace Utils {
const isTransparentFunctionHack = 'isTransparent(__value__)';
export const noRecursionHack = '__noRecursion';
- export const noDragsDocFilter = 'noDragDocs::any::check';
+
+ // special case filters
+ export const noDragDocsFilter = 'noDragDocs::any::check';
+ export const TransparentBackgroundFilter = `backgroundColor::${isTransparentFunctionHack},${noRecursionHack}::check`; // 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 const OpaqueBackgroundFilter = `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 IsRecursiveFilter(val: string) {
return !val.includes(noRecursionHack);
}
- export function HasTransparencyFilter(val: string) {
- return val.includes(isTransparentFunctionHack);
- }
- export function IsTransparentFilter() {
- // 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}::check`; // 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 IsOpaqueFilter() {
- // 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 IsPropUnsetFilter(prop: string) {
- return `${prop}::any,${noRecursionHack}::unset`;
+ export function HasFunctionFilter(val: string) {
+ if (val.includes(isTransparentFunctionHack)) return (color: string) => color !== '' && DashColor(color).alpha() !== 1;
+ // add other function filters here...
+ return undefined;
}
export function toRGBAstr(col: { r: number; g: number; b: number; a?: number }) {
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 4086ede20..c5a42aadc 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -1284,7 +1284,7 @@ export namespace DocUtils {
if (d.cookies && (!filterFacets.cookies || !Object.keys(filterFacets.cookies).some(key => d.cookies === key))) {
return false;
}
- for (const facetKey of Object.keys(filterFacets).filter(fkey => fkey !== 'cookies' && fkey !== Utils.noDragsDocFilter.split(Doc.FilterSep)[0])) {
+ for (const facetKey of Object.keys(filterFacets).filter(fkey => fkey !== 'cookies' && fkey !== Utils.noDragDocsFilter.split(Doc.FilterSep)[0])) {
const facet = filterFacets[facetKey];
// facets that match some value in the field of the document (e.g. some text field)
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 87ee1b252..ba3c26b42 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -339,7 +339,7 @@ export class CurrentUserUtils {
/// returns descriptions needed to buttons for the left sidebar to open up panes displaying different collections of documents
static leftSidebarMenuBtnDescriptions(doc: Doc):{title:string, target:Doc, icon:string, toolTip: string, scripts:{[key:string]:any}, funcs?:{[key:string]:any}, hidden?: boolean}[] {
- const badgeValue = "((len) => len && len !== '0' ? len: undefined)(docList(self.target.data).filter(doc => !docList(self.target.viewed).includes(doc)).length.toString())";
+ const badgeValue = "((len) => len && len !== '0' ? len: undefined)(docList(self.target?.data).filter(doc => !docList(self.target.viewed).includes(doc)).length.toString())";
const getActiveDashTrails = "Doc.ActiveDashboard?.myTrails";
return [
{ title: "Dashboards", toolTip: "Dashboards", target: this.setupDashboards(doc, "myDashboards"), ignoreClick: true, icon: "desktop", funcs: {hidden: "IsNoviceMode()"} },
diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts
index d0f66d124..fcf705ac0 100644
--- a/src/client/util/SelectionManager.ts
+++ b/src/client/util/SelectionManager.ts
@@ -1,6 +1,6 @@
-import { action, observable, ObservableMap } from 'mobx';
-import { computedFn } from 'mobx-utils';
+import { action, observable } from 'mobx';
import { Doc, Opt } from '../../fields/Doc';
+import { DocViews } from '../../fields/DocSymbols';
import { List } from '../../fields/List';
import { listSpec } from '../../fields/Schema';
import { Cast, DocCast } from '../../fields/Types';
@@ -12,9 +12,8 @@ import { UndoManager } from './UndoManager';
export namespace SelectionManager {
class Manager {
- @observable IsDragging: boolean = false;
- SelectedViewsMap: ObservableMap<DocumentView, Doc> = new ObservableMap();
@observable SelectedViews: DocumentView[] = [];
+ @observable IsDragging: boolean = false;
@observable SelectedSchemaDocument: Doc | undefined;
@action
@@ -24,27 +23,21 @@ export namespace SelectionManager {
@action
SelectView(docView: DocumentView, ctrlPressed: boolean): void {
// if doc is not in SelectedDocuments, add it
- if (!manager.SelectedViewsMap.get(docView)) {
- if (!ctrlPressed) {
- this.DeselectAll();
- }
-
+ if (!docView.SELECTED) {
+ if (!ctrlPressed) this.DeselectAll();
manager.SelectedViews.push(docView);
- manager.SelectedViewsMap.set(docView, docView.rootDoc);
- docView.props.whenChildContentsActiveChanged(true);
- } else if (!ctrlPressed && (Array.from(manager.SelectedViewsMap.entries()).length > 1 || manager.SelectedSchemaDocument)) {
- Array.from(manager.SelectedViewsMap.keys()).map(dv => dv !== docView && dv.props.whenChildContentsActiveChanged(false));
+ } else if (!ctrlPressed && (manager.SelectedViews.length > 1 || manager.SelectedSchemaDocument)) {
+ manager.SelectedViews.filter(dv => dv !== docView).forEach(dv => dv.props.whenChildContentsActiveChanged(false));
manager.SelectedSchemaDocument = undefined;
manager.SelectedViews.length = 0;
- manager.SelectedViewsMap.clear();
- manager.SelectedViews.push(docView);
- manager.SelectedViewsMap.set(docView, docView.rootDoc);
}
+ docView.SELECTED = true;
+ docView.props.whenChildContentsActiveChanged(true);
}
@action
DeselectView(docView?: DocumentView): void {
- if (docView && manager.SelectedViewsMap.get(docView)) {
- manager.SelectedViewsMap.delete(docView);
+ if (docView && manager.SelectedViews.includes(docView)) {
+ docView.SELECTED = false;
manager.SelectedViews.splice(manager.SelectedViews.indexOf(docView), 1);
docView.props.whenChildContentsActiveChanged(false);
}
@@ -54,8 +47,10 @@ export namespace SelectionManager {
LinkManager.currentLink = undefined;
LinkManager.currentLinkAnchor = undefined;
manager.SelectedSchemaDocument = undefined;
- Array.from(manager.SelectedViewsMap.keys()).forEach(dv => dv.props.whenChildContentsActiveChanged(false));
- manager.SelectedViewsMap.clear();
+ manager.SelectedViews.forEach(dv => {
+ dv.SELECTED = false;
+ dv.props.whenChildContentsActiveChanged(false);
+ });
manager.SelectedViews.length = 0;
}
}
@@ -74,45 +69,27 @@ export namespace SelectionManager {
manager.SelectSchemaViewDoc(document);
}
- const IsSelectedCache = computedFn(function isSelected(doc: DocumentView) {
- // wrapping get() in a computedFn only generates mobx() invalidations when the return value of the function for the specific get parameters has changed
- return manager.SelectedViewsMap.get(doc) ? true : false;
- });
// computed functions, such as used in IsSelected generate errors if they're called outside of a
// reaction context. Specifying the context with 'outsideReaction' allows an efficiency feature
// to avoid unnecessary mobx invalidations when running inside a reaction.
- export function IsSelected(doc: DocumentView | undefined, outsideReaction?: boolean): boolean {
- return !doc
- ? false
- : outsideReaction
- ? manager.SelectedViewsMap.get(doc)
- ? true
- : false // get() accesses a hashtable -- setting anything in the hashtable generates a mobx invalidation for every get()
- : IsSelectedCache(doc);
+ export function IsSelected(dv?: DocumentView | Doc): boolean {
+ return (dv instanceof Doc ? Array.from(dv[DocViews]) : dv ? [dv] : []).some(dv => dv?.SELECTED);
}
export function DeselectAll(except?: Doc): void {
- let found: DocumentView | undefined = undefined;
- if (except) {
- for (const view of Array.from(manager.SelectedViewsMap.keys())) {
- if (view.props.Document === except) found = view;
- }
- }
-
+ const found = manager.SelectedViews.find(dv => dv.Document === except);
manager.DeselectAll();
if (found) manager.SelectView(found, false);
}
export function Views(): Array<DocumentView> {
return manager.SelectedViews;
- // Array.from(manager.SelectedViewsMap.keys()); //.filter(dv => manager.SelectedViews.get(dv)?._type_collection !== CollectionViewType.Docking);
}
export function SelectedSchemaDoc(): Doc | undefined {
return manager.SelectedSchemaDocument;
}
export function Docs(): Doc[] {
return manager.SelectedViews.map(dv => dv.rootDoc).filter(doc => doc?._type_collection !== CollectionViewType.Docking);
- // Array.from(manager.SelectedViewsMap.values()).filter(doc => doc?._type_collection !== CollectionViewType.Docking);
}
}
ScriptingGlobals.add(function SelectionManager_selectedDocType(type: string, expertMode: boolean, checkContext?: boolean) {
diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index 483b92957..57cea77c9 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -1,10 +1,10 @@
import { action, computed, observable } from 'mobx';
import { DateField } from '../../fields/DateField';
-import { Doc, DocListCast, HierarchyMapping, Opt, ReverseHierarchyMap } from '../../fields/Doc';
-import { AclAdmin, AclAugment, AclEdit, AclPrivate, AclReadonly, DocAcl, DocData } from '../../fields/DocSymbols';
+import { Doc, DocListCast, Opt } from '../../fields/Doc';
+import { AclAdmin, AclAugment, AclEdit, AclPrivate, AclReadonly, DocData } from '../../fields/DocSymbols';
import { List } from '../../fields/List';
-import { Cast, DocCast, StrCast } from '../../fields/Types';
-import { distributeAcls, GetEffectiveAcl, inheritParentAcls, SharingPermissions } from '../../fields/util';
+import { Cast } from '../../fields/Types';
+import { GetEffectiveAcl, inheritParentAcls } from '../../fields/util';
import { returnFalse } from '../../Utils';
import { DocUtils } from '../documents/Documents';
import { DocumentType } from '../documents/DocumentTypes';
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index c6d3efd0c..72d7cd1c5 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -7,13 +7,13 @@ import { extname } from 'path';
import { BsArrowDown, BsArrowDownUp, BsArrowUp } from 'react-icons/bs';
import { FaFilter } from 'react-icons/fa';
import { Doc, Opt, StrListCast } from '../../fields/Doc';
+import { DocViews } from '../../fields/DocSymbols';
import { BoolCast, Cast, DocCast, ImageCast, NumCast, StrCast } from '../../fields/Types';
import { DashColor, lightOrDark, Utils } from '../../Utils';
import { CollectionViewType, DocumentType } from '../documents/DocumentTypes';
import { DocFocusOrOpen, DocumentManager } from '../util/DocumentManager';
import { IsFollowLinkScript } from '../util/LinkFollower';
import { LinkManager } from '../util/LinkManager';
-import { SelectionManager } from '../util/SelectionManager';
import { SettingsManager } from '../util/SettingsManager';
import { undoBatch, UndoManager } from '../util/UndoManager';
import { TreeSort } from './collections/TreeSort';
@@ -116,7 +116,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
case StyleProp.Highlighting:
if (doc && (Doc.IsSystem(doc) || doc.type === DocumentType.FONTICON)) return undefined;
if (doc && !doc.layout_disableBrushing && !props?.disableBrushing) {
- const selected = SelectionManager.Views().some(dv => dv.rootDoc === doc);
+ const selected = Array.from(doc?.[DocViews]??[]).filter(dv => dv.SELECTED).length;
const highlightIndex = Doc.isBrushedHighlightedDegree(doc) || (selected ? Doc.DocBrushStatus.selfBrushed : 0);
const highlightColor = ['transparent', 'rgb(68, 118, 247)', selected ? "black" : 'rgb(68, 118, 247)', 'orange', 'lightBlue'][highlightIndex];
const highlightStyle = ['solid', 'dashed', 'solid', 'solid', 'solid'][highlightIndex];
@@ -282,7 +282,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
const showFilterIcon =
StrListCast(doc?._childFilters).length || StrListCast(doc?._childFiltersByRanges).length
? 'green' // #18c718bd' //'hasFilter'
- : docProps?.childFilters?.().filter(f => Utils.IsRecursiveFilter(f) && f !== Utils.noDragsDocFilter).length || docProps?.childFiltersByRanges().length
+ : docProps?.childFilters?.().filter(f => Utils.IsRecursiveFilter(f) && f !== Utils.noDragDocsFilter).length || docProps?.childFiltersByRanges().length
? 'orange' //'inheritsFilter'
: undefined;
return !showFilterIcon ? null : (
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index 52cf40635..d0eadd9aa 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -557,25 +557,6 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewMenu
return this.props.type === CollectionViewType.Docking || (typeof layoutField === 'string' && !layoutField?.includes('CollectionView'));
} else return false;
}
- @computed
- get pinButton() {
- const targetDoc = this.selectedDoc;
- const isPinned = targetDoc && Doc.isDocPinned(targetDoc);
- return !targetDoc ? null : (
- <Tooltip key="pin" title={<div className="dash-tooltip">{Doc.isDocPinned(targetDoc) ? 'Unpin from presentation' : 'Pin to presentation'}</div>} placement="top">
- <button
- className="antimodeMenu-button"
- style={{ backgroundColor: isPinned ? '121212' : undefined, borderLeft: '1px solid gray' }}
- onClick={e =>
- TabDocView.PinDoc(targetDoc, {
- /* unpin: isPinned*/
- })
- }>
- <FontAwesomeIcon className="colMenu-icon" size="lg" icon="map-pin" />
- </button>
- </Tooltip>
- );
- }
@undoBatch
@action
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 8a1ba0df1..e9192ebbe 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -125,7 +125,7 @@ export function CollectionSubView<X>(moreProps?: X) {
const docsforFilter: Doc[] = [];
childDocs.forEach(d => {
// dragging facets
- const dragged = this.props.childFilters?.().some(f => f.includes(Utils.noDragsDocFilter));
+ const dragged = this.props.childFilters?.().some(f => f.includes(Utils.noDragDocsFilter));
if (dragged && SnappingManager.GetCanEmbed() && DragManager.docsBeingDragged.includes(d)) return false;
let notFiltered = d.z || Doc.IsSystem(d) || DocUtils.FilterDocs([d], this.unrecursiveDocFilters(), childFiltersByRanges, this.props.Document).length > 0;
if (notFiltered) {
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 26aa5a121..41f3b2603 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -53,7 +53,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
@observable _isActive: boolean = false;
@observable _isAnyChildContentActive = false;
@computed get _isUserActivated() {
- return SelectionManager.Views().some(view => view.rootDoc === this._document) || this._isAnyChildContentActive;
+ return SelectionManager.IsSelected(this._document) || this._isAnyChildContentActive;
}
@computed get _isContentActive() {
return this._isUserActivated || this._hovering;
@@ -203,7 +203,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
}
});
tab._disposers.selectionDisposer = reaction(
- () => SelectionManager.Views().some(view => view.rootDoc === this._document),
+ () => SelectionManager.IsSelected(this._document),
action(selected => {
if (selected) this._activated = true;
const toggle = tab.element[0].children[2].children[0] as HTMLInputElement;
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
index 24a758d8c..aca6df3c9 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
@@ -1,7 +1,7 @@
import { action, computed, IReactionDisposer, observable, reaction } from 'mobx';
import { observer } from 'mobx-react';
import { Doc, Field } from '../../../../fields/Doc';
-import { DocCss } from '../../../../fields/DocSymbols';
+import { Brushed, DocCss } from '../../../../fields/DocSymbols';
import { Id } from '../../../../fields/FieldSymbols';
import { List } from '../../../../fields/List';
import { Cast, NumCast, StrCast } from '../../../../fields/Types';
@@ -223,8 +223,8 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
const pt2normlen = Math.sqrt(pt2norm[0] * pt2norm[0] + pt2norm[1] * pt2norm[1]) || 1;
const pt1normalized = [pt1norm[0] / pt1normlen, pt1norm[1] / pt1normlen];
const pt2normalized = [pt2norm[0] / pt2normlen, pt2norm[1] / pt2normlen];
- const aActive = A.isSelected() || Doc.IsBrushed(A.rootDoc);
- const bActive = B.isSelected() || Doc.IsBrushed(B.rootDoc);
+ const aActive = A.isSelected() || A.rootDoc[Brushed];
+ const bActive = B.isSelected() || B.rootDoc[Brushed];
const textX = (Math.min(pt1[0], pt2[0]) + Math.max(pt1[0], pt2[0])) / 2 + NumCast(LinkDocs[0].link_relationship_OffsetX);
const textY = (pt1[1] + pt2[1]) / 2 + NumCast(LinkDocs[0].link_relationship_OffsetY);
@@ -239,11 +239,11 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
textX,
textY,
// fully connected
- // pt1,
- // pt2,
+ // pt1,
+ // pt2,
// this code adds space between links
- pt1: link.link_displayArrow ? [pt1[0] + pt1normalized[0] * 3*NumCast(link.link_displayArrow_scale, 4), pt1[1] + pt1normalized[1] * 3*NumCast(link.link_displayArrow_scale, 3)] : pt1,
- pt2: link.link_displayArrow ? [pt2[0] + pt2normalized[0] * 3*NumCast(link.link_displayArrow_scale, 4), pt2[1] + pt2normalized[1] * 3*NumCast(link.link_displayArrow_scale, 3)] : pt2,
+ pt1: link.link_displayArrow ? [pt1[0] + pt1normalized[0] * 3 * NumCast(link.link_displayArrow_scale, 4), pt1[1] + pt1normalized[1] * 3 * NumCast(link.link_displayArrow_scale, 3)] : pt1,
+ pt2: link.link_displayArrow ? [pt2[0] + pt2normalized[0] * 3 * NumCast(link.link_displayArrow_scale, 4), pt2[1] + pt2normalized[1] * 3 * NumCast(link.link_displayArrow_scale, 3)] : pt2,
};
}
@@ -269,12 +269,12 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
//thickness varies linearly from 3px to 12px for increasing link count
const strokeWidth = linkSize === -1 ? '3px' : Math.floor(2 + 10 * (linkSize / Math.max(...linkRelationshipSizes))) + 'px';
- const arrowScale = NumCast(link.link_displayArrow_scale, 3)
+ const arrowScale = NumCast(link.link_displayArrow_scale, 3);
return link.opacity === 0 || !a.width || !b.width || (!(Doc.UserDoc().showLinkLines || link.link_displayLine) && !aActive && !bActive) ? null : (
<>
<defs>
- <marker id={`${link[Id] + 'arrowhead'}`} markerWidth={`${4*arrowScale}`} markerHeight={`${3*arrowScale}`} refX="0" refY={`${1.5*arrowScale}`} orient="auto">
- <polygon points={`0 0, ${3*arrowScale} ${1.5*arrowScale}, 0 ${3*arrowScale}`} fill={stroke} />
+ <marker id={`${link[Id] + 'arrowhead'}`} markerWidth={`${4 * arrowScale}`} markerHeight={`${3 * arrowScale}`} refX="0" refY={`${1.5 * arrowScale}`} orient="auto">
+ <polygon points={`0 0, ${3 * arrowScale} ${1.5 * arrowScale}, 0 ${3 * arrowScale}`} fill={stroke} />
</marker>
<filter id="outline">
<feMorphology in="SourceAlpha" result="expanded" operator="dilate" radius="1" />
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index f73c037f4..ce63a2cf2 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -86,7 +86,17 @@ export class CollectionSchemaView extends CollectionSubView() {
}
@computed get _selectedDocs() {
- return SelectionManager.Docs().filter(doc => Doc.AreProtosEqual(DocCast(doc.embedContainer), this.rootDoc));
+ const selected = SelectionManager.Docs().filter(doc => Doc.AreProtosEqual(DocCast(doc.embedContainer), this.rootDoc));
+ if (!selected.length) {
+ for (const sel of SelectionManager.Docs()) {
+ const contextPath = DocumentManager.GetContextPath(sel, true);
+ if (contextPath.includes(this.rootDoc)) {
+ const parentInd = contextPath.indexOf(this.rootDoc);
+ return parentInd < contextPath.length - 1 ? [contextPath[parentInd + 1]] : [];
+ }
+ }
+ }
+ return selected;
}
@computed get documentKeys() {
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 98b13f90f..d87efb7b1 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -5,7 +5,7 @@ import { observer } from 'mobx-react';
import { computedFn } from 'mobx-utils';
import { Bounce, Fade, Flip, LightSpeed, Roll, Rotate, Zoom } from 'react-reveal';
import { Doc, DocListCast, Field, Opt, StrListCast } from '../../../fields/Doc';
-import { AclPrivate, Animation, AudioPlay, DocData, Width } from '../../../fields/DocSymbols';
+import { AclPrivate, Animation, AudioPlay, DocData, DocViews, Width } from '../../../fields/DocSymbols';
import { Id } from '../../../fields/FieldSymbols';
import { InkTool } from '../../../fields/InkField';
import { List } from '../../../fields/List';
@@ -900,7 +900,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
@computed get _rootSelected() {
return this.props.isSelected(false) || (this.props.Document.rootDocument && this.props.rootSelected?.(false)) || false;
}
- rootSelected = (outsideReaction?: boolean) => this._rootSelected;
+ rootSelected = () => this._rootSelected;
panelHeight = () => this.props.PanelHeight() - this.headerMargin;
screenToLocal = () => this.props.ScreenToLocalTransform().translate(0, -this.headerMargin);
onClickFunc: any = () => (this.disableClickScriptFunc ? undefined : this.onClickHandler);
@@ -1345,6 +1345,13 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
@observer
export class DocumentView extends React.Component<DocumentViewProps> {
public static ROOT_DIV = 'documentView-effectsWrapper';
+ @observable _selected = false;
+ public get SELECTED() {
+ return this._selected;
+ }
+ public set SELECTED(val) {
+ this._selected = val;
+ }
@observable public static Interacting = false;
@observable public static LongPress = false;
@observable public static ExploreMode = false;
@@ -1579,7 +1586,7 @@ export class DocumentView extends React.Component<DocumentViewProps> {
scaleToScreenSpace = () => (1 / (this.props.NativeDimScaling?.() || 1)) * this.screenToLocalTransform().Scale;
docViewPathFunc = () => this.docViewPath;
- isSelected = (outsideReaction?: boolean) => SelectionManager.IsSelected(this, outsideReaction);
+ isSelected = () => SelectionManager.IsSelected(this);
select = (extendSelection: boolean, focusSelection?: boolean) => {
SelectionManager.SelectView(this, extendSelection);
if (focusSelection) {
@@ -1602,7 +1609,10 @@ export class DocumentView extends React.Component<DocumentViewProps> {
.ScreenToLocalTransform()
.translate(-this.centeringX, -this.centeringY)
.scale(this.trueNativeWidth() ? 1 / this.nativeScaling : 1);
+
+ @action
componentDidMount() {
+ this.rootDoc[DocViews].add(this);
this._disposers.updateContentsScript = reaction(
() => ScriptCast(this.rootDoc.updateContentsScript)?.script?.run({ this: this.props.Document, self: Cast(this.rootDoc, Doc, null) || this.props.Document }).result,
output => output
@@ -1617,7 +1627,9 @@ export class DocumentView extends React.Component<DocumentViewProps> {
);
!BoolCast(this.props.Document.dontRegisterView, this.props.dontRegisterView) && DocumentManager.Instance.AddView(this);
}
+ @action
componentWillUnmount() {
+ this.rootDoc[DocViews].delete(this);
Object.values(this._disposers).forEach(disposer => disposer?.());
!BoolCast(this.props.Document.dontRegisterView, this.props.dontRegisterView) && DocumentManager.Instance.RemoveView(this);
}
diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx
index 50b070e7f..08dda2e1f 100644
--- a/src/client/views/nodes/MapBox/MapBox.tsx
+++ b/src/client/views/nodes/MapBox/MapBox.tsx
@@ -307,8 +307,8 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
panelWidth = () => this.props.PanelWidth() / (this.props.NativeDimScaling?.() || 1) - this.sidebarWidth();
panelHeight = () => this.props.PanelHeight() / (this.props.NativeDimScaling?.() || 1);
scrollXf = () => this.props.ScreenToLocalTransform().translate(0, NumCast(this.layoutDoc._layout_scrollTop));
- transparentFilter = () => [...this.props.childFilters(), Utils.IsTransparentFilter()];
- opaqueFilter = () => [...this.props.childFilters(), Utils.IsOpaqueFilter()];
+ transparentFilter = () => [...this.props.childFilters(), Utils.TransparentBackgroundFilter];
+ opaqueFilter = () => [...this.props.childFilters(), Utils.OpaqueBackgroundFilter];
infoWidth = () => this.props.PanelWidth() / 5;
infoHeight = () => this.props.PanelHeight() / 5;
anchorMenuClick = () => this._sidebarRef.current?.anchorMenuClick;
diff --git a/src/client/views/nodes/MapBox/MapBox2.tsx b/src/client/views/nodes/MapBox/MapBox2.tsx
index 407a91dd0..d38857d90 100644
--- a/src/client/views/nodes/MapBox/MapBox2.tsx
+++ b/src/client/views/nodes/MapBox/MapBox2.tsx
@@ -547,8 +547,8 @@ export class MapBox2 extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
panelWidth = () => this.props.PanelWidth() / (this.props.NativeDimScaling?.() || 1) - this.sidebarWidth();
panelHeight = () => this.props.PanelHeight() / (this.props.NativeDimScaling?.() || 1);
scrollXf = () => this.props.ScreenToLocalTransform().translate(0, NumCast(this.layoutDoc._layout_scrollTop));
- transparentFilter = () => [...this.props.childFilters(), Utils.IsTransparentFilter()];
- opaqueFilter = () => [...this.props.childFilters(), Utils.IsOpaqueFilter()];
+ transparentFilter = () => [...this.props.childFilters(), Utils.TransparentBackgroundFilter];
+ opaqueFilter = () => [...this.props.childFilters(), Utils.OpaqueBackgroundFilter];
infoWidth = () => this.props.PanelWidth() / 5;
infoHeight = () => this.props.PanelHeight() / 5;
anchorMenuClick = () => this._sidebarRef.current?.anchorMenuClick;
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index 2aca314da..5c526fe38 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -1053,8 +1053,8 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
panelHeight = () => this.props.PanelHeight() / (this.props.NativeDimScaling?.() || 1);
scrollXf = () => this.props.ScreenToLocalTransform().translate(0, NumCast(this.layoutDoc._layout_scrollTop));
anchorMenuClick = () => this._sidebarRef.current?.anchorMenuClick;
- transparentFilter = () => [...this.props.childFilters(), Utils.IsTransparentFilter()];
- opaqueFilter = () => [...this.props.childFilters(), Utils.noDragsDocFilter, ...(SnappingManager.GetCanEmbed() ? [] : [Utils.IsOpaqueFilter()])];
+ transparentFilter = () => [...this.props.childFilters(), Utils.TransparentBackgroundFilter];
+ opaqueFilter = () => [...this.props.childFilters(), Utils.noDragDocsFilter, ...(SnappingManager.GetCanEmbed() ? [] : [Utils.OpaqueBackgroundFilter])];
childStyleProvider = (doc: Doc | undefined, props: Opt<DocumentViewProps>, property: string): any => {
if (doc instanceof Doc && property === StyleProp.PointerEvents) {
if (this.inlineTextAnnotations.includes(doc)) return 'none';
diff --git a/src/client/views/pdf/Annotation.tsx b/src/client/views/pdf/Annotation.tsx
index 52904b852..17a8048e9 100644
--- a/src/client/views/pdf/Annotation.tsx
+++ b/src/client/views/pdf/Annotation.tsx
@@ -90,7 +90,7 @@ class RegionAnnotation extends React.Component<IRegionAnnotationProps> {
@computed get linkHighlighted() {
for (const link of LinkManager.Instance.getAllDirectLinks(this.props.document)) {
const a1 = LinkManager.getOppositeAnchor(link, this.props.document);
- if (a1 && Doc.IsBrushedDegreeUnmemoized(DocCast(a1.annotationOn, this.props.document))) return true;
+ if (a1 && Doc.IsBrushedDegree(DocCast(a1.annotationOn, this.props.document))) return true;
}
}
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 43b662f0f..c1b2749fb 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -110,13 +110,7 @@ export class PDFViewer extends React.Component<IViewerProps> {
this._disposers.selected = reaction(
() => this.props.isSelected(),
- selected => {
- // if (!selected) {
- // Array.from(this._savedAnnotations.values()).forEach(v => v.forEach(a => a.remove()));
- // Array.from(this._savedAnnotations.keys()).forEach(k => this._savedAnnotations.set(k, []));
- // }
- SelectionManager.Views().length === 1 && this.setupPdfJsViewer();
- },
+ selected => SelectionManager.Views().length === 1 && this.setupPdfJsViewer(),
{ fireImmediately: true }
);
this._disposers.curPage = reaction(
@@ -509,8 +503,8 @@ export class PDFViewer extends React.Component<IViewerProps> {
overlayTransform = () => this.scrollXf().scale(1 / NumCast(this.props.layoutDoc._freeform_scale, 1));
panelWidth = () => this.props.PanelWidth() / (this.props.NativeDimScaling?.() || 1);
panelHeight = () => this.props.PanelHeight() / (this.props.NativeDimScaling?.() || 1);
- transparentFilter = () => [...this.props.childFilters(), Utils.IsTransparentFilter()];
- opaqueFilter = () => [...this.props.childFilters(), Utils.noDragsDocFilter, ...(SnappingManager.GetCanEmbed() && this.props.isContentActive() ? [] : [Utils.IsOpaqueFilter()])];
+ transparentFilter = () => [...this.props.childFilters(), Utils.TransparentBackgroundFilter];
+ opaqueFilter = () => [...this.props.childFilters(), Utils.noDragDocsFilter, ...(SnappingManager.GetCanEmbed() && this.props.isContentActive() ? [] : [Utils.OpaqueBackgroundFilter])];
childStyleProvider = (doc: Doc | undefined, props: Opt<DocumentViewProps>, property: string): any => {
if (doc instanceof Doc && property === StyleProp.PointerEvents) {
if (this.inlineTextAnnotations.includes(doc) || this.props.isContentActive() === false) return 'none';
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index feacdc9c5..2f9eea492 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -11,7 +11,7 @@ import { afterDocDeserialize, autoObject, Deserializable, SerializationHelper }
import { undoable } from '../client/util/UndoManager';
import { decycle } from '../decycler/decycler';
import * as JSZipUtils from '../JSZipUtils';
-import { DashColor, incrementTitleCopy, intersectRect, Utils } from '../Utils';
+import { incrementTitleCopy, intersectRect, Utils } from '../Utils';
import { DateField } from './DateField';
import {
AclAdmin,
@@ -21,6 +21,7 @@ import {
AclReadonly,
Animation,
AudioPlay,
+ Brushed,
CachedUpdates,
DirectLinks,
DocAcl,
@@ -28,6 +29,7 @@ import {
DocData,
DocFields,
DocLayout,
+ DocViews,
FieldKeys,
FieldTuples,
ForceServerWrite,
@@ -52,6 +54,7 @@ import { BoolCast, Cast, DocCast, FieldValue, NumCast, StrCast, ToConstructor }
import { AudioField, CsvField, ImageField, PdfField, VideoField, WebField } from './URLField';
import { containedFieldChangedHandler, deleteProperty, GetEffectiveAcl, getField, getter, makeEditable, makeReadOnly, normalizeEmail, setter, SharingPermissions, TraceMobx } from './util';
import JSZip = require('jszip');
+import { DocumentView } from '../client/views/nodes/DocumentView';
export const LinkedTo = '-linkedTo';
export namespace Field {
export function toKeyValueString(doc: Doc, key: string): string {
@@ -354,6 +357,8 @@ export class Doc extends RefField {
@observable public [AudioPlay]: any; // meant to store sound object from Howl
@observable public [Animation]: Opt<Doc>;
@observable public [Highlight]: boolean = false;
+ @observable public [Brushed]: boolean = false;
+ @observable public [DocViews] = new ObservableSet<DocumentView>();
static __Anim(Doc: Doc) {
// for debugging to print AnimationSym field easily.
return Doc[Animation];
@@ -808,9 +813,7 @@ export namespace Doc {
const docAtKey = DocCast(clone[key]);
if (docAtKey && !Doc.IsSystem(docAtKey)) {
if (!Array.from(cloneMap.values()).includes(docAtKey)) {
- if (cloneMap.has(docAtKey[Id])) {
- clone[key] = cloneMap.get(docAtKey[Id]);
- } else clone[key] = undefined;
+ clone[key] = cloneMap.get(docAtKey[Id]);
} else {
repairClone(docAtKey, cloneMap, visited);
}
@@ -1020,7 +1023,7 @@ export namespace Doc {
references.add(doc);
return;
}
- const excludeLists = ['My Recently Closed', 'My Header Bar', 'My Dashboards'].includes(StrCast(doc.title));
+ const excludeLists = [Doc.MyRecentlyClosed, Doc.MyHeaderBar, Doc.MyDashboards].includes(doc);
if (system !== undefined && ((system && !Doc.IsSystem(doc)) || (!system && Doc.IsSystem(doc)))) return;
references.add(doc);
Object.keys(doc).forEach(key => {
@@ -1202,9 +1205,6 @@ export namespace Doc {
// change it to render the target metadata field instead of what it was rendering before and assign it to the template field layout document.
Doc.Layout(templateField).layout = templateFieldLayoutString.replace(/fieldKey={'[^']*'}/, `fieldKey={'${metadataFieldKey}'}`);
- // assign the template field doc a delegate of any extension document that was previously used to render the template field (since extension doc's carry rendering informatino)
- Doc.Layout(templateField)[metadataFieldKey + '_ext'] = Doc.MakeDelegate(templateField[templateFieldLayoutString?.split("'")[1] + '_ext'] as Doc);
-
return true;
}
@@ -1234,13 +1234,13 @@ export namespace Doc {
export function isBrushedHighlightedDegree(doc: Doc) {
return Doc.IsHighlighted(doc) ? DocBrushStatus.highlighted : Doc.IsBrushedDegree(doc);
}
- export function isBrushedHighlightedDegreeUnmemoized(doc: Doc) {
- return Doc.IsHighlighted(doc) ? DocBrushStatus.highlighted : Doc.IsBrushedDegreeUnmemoized(doc);
- }
-
export class DocBrush {
- BrushedDoc: ObservableMap<Doc, boolean> = new ObservableMap();
+ BrushedDoc = new Set<Doc>();
SearchMatchDoc: ObservableMap<Doc, { searchMatch: number }> = new ObservableMap();
+ brushDoc = action((doc: Doc, unbrush: boolean) => {
+ unbrush ? this.BrushedDoc.delete(doc) : this.BrushedDoc.add(doc);
+ doc[Brushed] = !unbrush;
+ });
}
export const brushManager = new DocBrush();
@@ -1330,45 +1330,25 @@ export namespace Doc {
brushManager.SearchMatchDoc.clear();
}
- const isBrushedCache = computedFn(function IsBrushed(doc: Doc) {
- return brushManager.BrushedDoc.has(doc) || brushManager.BrushedDoc.has(Doc.GetProto(doc));
- });
- export function IsBrushed(doc: Doc) {
- return isBrushedCache(doc);
- }
-
export enum DocBrushStatus {
unbrushed = 0,
protoBrushed = 1,
selfBrushed = 2,
highlighted = 3,
}
- // don't bother memoizing (caching) the result if called from a non-reactive context. (plus this avoids a warning message)
- export function IsBrushedDegreeUnmemoized(doc: Doc) {
- if (!doc || GetEffectiveAcl(doc) === AclPrivate || GetEffectiveAcl(Doc.GetProto(doc)) === AclPrivate || doc.opacity === 0) return DocBrushStatus.unbrushed;
- const status = brushManager.BrushedDoc.has(doc) ? DocBrushStatus.selfBrushed : brushManager.BrushedDoc.has(Doc.GetProto(doc)) ? DocBrushStatus.protoBrushed : DocBrushStatus.unbrushed;
- return status;
- }
+ // returns 'how' a Doc has been brushed over - whether the document itself was brushed, it's prototype, or neither
export function IsBrushedDegree(doc: Doc) {
- return computedFn(function IsBrushDegree(doc: Doc) {
- return Doc.IsBrushedDegreeUnmemoized(doc);
- })(doc);
+ if (!doc || GetEffectiveAcl(doc) === AclPrivate || GetEffectiveAcl(Doc.GetProto(doc)) === AclPrivate || doc.opacity === 0) return DocBrushStatus.unbrushed;
+ return doc[Brushed] ? DocBrushStatus.selfBrushed : Doc.GetProto(doc)[Brushed] ? DocBrushStatus.protoBrushed : DocBrushStatus.unbrushed;
}
- export function BrushDoc(doc: Doc) {
+ export function BrushDoc(doc: Doc, unbrush = false) {
if (!doc || GetEffectiveAcl(doc) === AclPrivate || GetEffectiveAcl(Doc.GetProto(doc)) === AclPrivate) return doc;
- runInAction(() => {
- brushManager.BrushedDoc.set(doc, true);
- brushManager.BrushedDoc.set(Doc.GetProto(doc), true);
- });
+ brushManager.brushDoc(doc, unbrush);
+ brushManager.brushDoc(Doc.GetProto(doc), unbrush);
return doc;
}
export function UnBrushDoc(doc: Doc) {
- if (!doc || GetEffectiveAcl(doc) === AclPrivate || GetEffectiveAcl(Doc.GetProto(doc)) === AclPrivate) return doc;
- runInAction(() => {
- brushManager.BrushedDoc.delete(doc);
- brushManager.BrushedDoc.delete(Doc.GetProto(doc));
- });
- return doc;
+ return BrushDoc(doc, true);
}
export function LinkEndpoint(linkDoc: Doc, anchorDoc: Doc) {
@@ -1436,7 +1416,7 @@ export namespace Doc {
});
}
export function UnBrushAllDocs() {
- runInAction(() => brushManager.BrushedDoc.clear());
+ Array.from(brushManager.BrushedDoc).forEach(action(doc => (doc[Brushed] = false)));
}
export function getDocTemplate(doc?: Doc) {
@@ -1454,9 +1434,9 @@ export namespace Doc {
}
export function matchFieldValue(doc: Doc, key: string, value: any): boolean {
- if (Utils.HasTransparencyFilter(value)) {
- const isTransparent = (color: string) => color !== '' && DashColor(color).alpha() !== 1;
- return isTransparent(StrCast(doc[key]));
+ const hasFunctionFilter = Utils.HasFunctionFilter(value);
+ if (hasFunctionFilter) {
+ return hasFunctionFilter(StrCast(doc[key]));
}
if (key === LinkedTo) {
// links are not a field value, so handled here. value is an expression of form ([field=]idToDoc("..."))
@@ -1481,11 +1461,9 @@ export namespace Doc {
(value === Doc.FilterNone && fieldVal === undefined)) {
return true;
}
- if (Cast(fieldVal, listSpec('string'), []).length) {
- const vals = StrListCast(fieldVal);
- const docs = vals.some(v => (v as any) instanceof Doc);
- if (docs) return value === Field.toString(fieldVal as Field);
- return vals.some(v => v.includes(value)); // bcz: arghh: Todo: comparison should be parameterized as exact, or substring
+ const vals = StrListCast(fieldVal); // list typing is very imperfect. casting to a string list doesn't mean that the entries will actually be strings
+ if (vals.length) {
+ return vals.some(v => typeof v === 'string' && v.includes(value)); // bcz: arghh: Todo: comparison should be parameterized as exact, or substring
}
return Field.toString(fieldVal as Field).includes(value); // bcz: arghh: Todo: comparison should be parameterized as exact, or substring
}
@@ -1501,34 +1479,27 @@ export namespace Doc {
doc.layout_fieldKey = deiconify || 'layout';
}
export function setDocRangeFilter(container: Opt<Doc>, key: string, range?: readonly number[], modifiers?: 'remove') {
- //, modifiers: 'remove' | 'set'
if (!container) return;
const childFiltersByRanges = Cast(container._childFiltersByRanges, listSpec('string'), []);
for (let i = 0; i < childFiltersByRanges.length; i += 3) {
if (childFiltersByRanges[i] === key) {
- console.log('this is key inside childfilters by range ' + key);
childFiltersByRanges.splice(i, 3);
- console.log('this is child filters by range ' + childFiltersByRanges);
break;
}
}
if (range !== undefined) {
- console.log('in doc.ts in set range filter');
childFiltersByRanges.push(key);
childFiltersByRanges.push(range[0].toString());
childFiltersByRanges.push(range[1].toString());
container._childFiltersByRanges = new List<string>(childFiltersByRanges);
- console.log('this is child filters by range ' + childFiltersByRanges[0] + ',' + childFiltersByRanges[1] + ',' + childFiltersByRanges[2]);
- console.log('this is new list ' + container._childFiltersByRange);
}
if (modifiers) {
childFiltersByRanges.splice(0, 3);
container._childFiltersByRanges = new List<string>(childFiltersByRanges);
}
- console.log('this is child filters by range END' + childFiltersByRanges[0] + ',' + childFiltersByRanges[1] + ',' + childFiltersByRanges[2]);
}
export const FilterSep = '::';
@@ -1599,12 +1570,6 @@ export namespace Doc {
});
}
- export function isDocPinned(doc: Doc) {
- //add this new doc to props.Document
- const curPres = Doc.ActivePresentation;
- return !curPres ? false : DocListCast(curPres.data).findIndex(val => Doc.AreProtosEqual(val, doc)) !== -1;
- }
-
export function styleFromLayoutString(rootDoc: Doc, layoutDoc: Doc, props: any, scale: number) {
const style: { [key: string]: any } = {};
const divKeys = ['width', 'height', 'fontSize', 'transform', 'left', 'backgroundColor', 'left', 'right', 'top', 'bottom', 'pointerEvents', 'position'];
@@ -1628,7 +1593,7 @@ export namespace Doc {
if (ptx !== undefined && pty !== undefined && newPoint !== undefined) {
const firstx = list.length ? NumCast(list[0].x) + ptx - newPoint[0] : 0;
const firsty = list.length ? NumCast(list[0].y) + pty - newPoint[1] : 0;
- docs.map(doc => {
+ docs.forEach(doc => {
doc.x = NumCast(doc.x) - firstx;
doc.y = NumCast(doc.y) - firsty;
});
@@ -1871,10 +1836,6 @@ ScriptingGlobals.add(function setInPlace(doc: any, field: any, value: any) {
ScriptingGlobals.add(function sameDocs(doc1: any, doc2: any) {
return Doc.AreProtosEqual(doc1, doc2);
});
-ScriptingGlobals.add(function DOC(id: string) {
- console.log("Can't parse a document id in a script");
- return 'invalid';
-});
ScriptingGlobals.add(function assignDoc(doc: Doc, field: string, id: string) {
return Doc.assignDocToField(doc, field, id);
});
diff --git a/src/fields/DocSymbols.ts b/src/fields/DocSymbols.ts
index df74cc9fe..87f186a23 100644
--- a/src/fields/DocSymbols.ts
+++ b/src/fields/DocSymbols.ts
@@ -8,6 +8,8 @@ export const Width = Symbol('DocWidth');
export const Height = Symbol('DocHeight');
export const Animation = Symbol('DocAnimation');
export const Highlight = Symbol('DocHighlight');
+export const DocViews = Symbol('DocViews');
+export const Brushed = Symbol('DocBrushed');
export const DocData = Symbol('DocData');
export const DocLayout = Symbol('DocLayout');
export const DocFields = Symbol('DocFields');
diff --git a/src/fields/Types.ts b/src/fields/Types.ts
index 69dbe9756..337e8ca21 100644
--- a/src/fields/Types.ts
+++ b/src/fields/Types.ts
@@ -1,6 +1,7 @@
import { DateField } from './DateField';
import { Doc, Field, FieldResult, Opt } from './Doc';
import { List } from './List';
+import { ProxyField } from './Proxy';
import { RefField } from './RefField';
import { RichTextField } from './RichTextField';
import { ScriptField } from './ScriptField';
@@ -72,6 +73,8 @@ export function Cast<T extends CastCtor>(field: FieldResult, ctor: T, defaultVal
}
} else if (field instanceof (ctor as any)) {
return field as ToType<T>;
+ } else if (field instanceof ProxyField && field.value instanceof (ctor as any)) {
+ return field.value as ToType<T>;
}
}
return defaultVal === null ? undefined : defaultVal;