From c260df7a30a5601d784fe9ccaccd805fbefde51d Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 18 Sep 2020 10:27:18 -0400 Subject: changed ACL to acl. fixed title to read values from data doc preferentially over layout doc. --- src/fields/Doc.ts | 10 +++++----- src/fields/Schema.ts | 2 +- src/fields/util.ts | 14 +++++++------- 3 files changed, 13 insertions(+), 13 deletions(-) (limited to 'src/fields') diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index a8950f1ee..ba7c9c7da 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -121,7 +121,7 @@ const AclMap = new Map([ export function fetchProto(doc: Doc) { 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; @@ -253,7 +253,7 @@ export class Doc extends RefField { const prev = GetEffectiveAcl(this); this[UpdatingFromServer] = true; this[fKey] = value; - if (fKey.startsWith("ACL")) { + if (fKey.startsWith("acl")) { fetchProto(this); } this[UpdatingFromServer] = false; @@ -261,7 +261,7 @@ export class Doc extends RefField { DocServer.GetRefField(this[Id], true); } }; - if (sameAuthor || fKey.startsWith("ACL") || DocServer.getFieldWriteMode(fKey) !== DocServer.WriteMode.Playground) { + if (sameAuthor || fKey.startsWith("acl") || DocServer.getFieldWriteMode(fKey) !== DocServer.WriteMode.Playground) { delete this[CachedUpdates][fKey]; await fn(); } else { @@ -775,7 +775,7 @@ export namespace Doc { } }); copy.author = Doc.CurrentUserEmail; - Doc.UserDoc().defaultAclPrivate && (copy["ACL-Public"] = "Not Shared"); + Doc.UserDoc().defaultAclPrivate && (copy["acl-Public"] = "Not Shared"); return copy; } @@ -803,7 +803,7 @@ export namespace Doc { const applied = ApplyTemplateTo(templateDoc, target, targetKey, templateDoc.title + "(..." + _applyCount++ + ")"); target.layoutKey = targetKey; applied && (Doc.GetProto(applied).type = templateDoc.type); - Doc.UserDoc().defaultAclPrivate && (applied["ACL-Public"] = "Not Shared"); + Doc.UserDoc().defaultAclPrivate && (applied["acl-Public"] = "Not Shared"); return applied; } return undefined; diff --git a/src/fields/Schema.ts b/src/fields/Schema.ts index 23ac50f74..4607e0fd5 100644 --- a/src/fields/Schema.ts +++ b/src/fields/Schema.ts @@ -52,7 +52,7 @@ export function makeInterface(...schemas: T): InterfaceFu return field; }, set(target: any, prop, value, receiver) { - receiver.doc && (receiver.doc[prop] = value); // receiver.doc may be undefined as the result of a change in ACLs + receiver.doc && (receiver.doc[prop] = value); // receiver.doc may be undefined as the result of a change in acls return true; } }); diff --git a/src/fields/util.ts b/src/fields/util.ts index 82525f92b..00e1683bd 100644 --- a/src/fields/util.ts +++ b/src/fields/util.ts @@ -111,7 +111,7 @@ export function makeEditable() { _setter = _setterImpl; } var _overrideAcl = false; -export function OVERRIDE_ACL(val: boolean) { +export function OVERRIDE_acl(val: boolean) { _overrideAcl = val; } @@ -168,7 +168,7 @@ export function GetEffectiveAcl(target: any, in_prop?: string | symbol | number, if (currentUserGroups.includes("Admin")) return AclAdmin; - // if the ACL is being overriden or the property being modified is one of the playground fields (which can be freely modified) + // if the acl is being overriden or the property being modified is one of the playground fields (which can be freely modified) if (_overrideAcl || (in_prop && DocServer.PlaygroundFields?.includes(in_prop.toString()))) return AclEdit; let effectiveAcl = AclPrivate; @@ -198,11 +198,11 @@ export function GetEffectiveAcl(target: any, in_prop?: string | symbol | number, } /** * Recursively distributes the access right for a user across the children of a document and its annotations. - * @param key the key storing the access right (e.g. ACL-groupname) + * @param key the key storing the access right (e.g. acl-groupname) * @param acl the access right being stored (e.g. "Can Edit") * @param target the document on which this access right is being set - * @param inheritingFromCollection whether the target is being assigned rights after being dragged into a collection (and so is inheriting the ACLs from the collection) - * inheritingFromCollection is not currently being used but could be used if ACL assignment defaults change + * @param inheritingFromCollection whether the target is being assigned rights after being dragged into a collection (and so is inheriting the acls from the collection) + * inheritingFromCollection is not currently being used but could be used if acl assignment defaults change */ export function distributeAcls(key: string, acl: SharingPermissions, target: Doc, inheritingFromCollection?: boolean) { @@ -271,8 +271,8 @@ export function setter(target: any, in_prop: string | symbol | number, value: an if (effectiveAcl !== AclEdit && effectiveAcl !== AclAdmin) return true; // if you're trying to change an acl but don't have Admin access / you're trying to change it to something that isn't an acceptable acl, you can't - if (typeof prop === "string" && prop.startsWith("ACL") && (effectiveAcl !== AclAdmin || ![...Object.values(SharingPermissions), undefined].includes(value))) return true; - // if (typeof prop === "string" && prop.startsWith("ACL") && !["Can Edit", "Can Add", "Can View", "Not Shared", undefined].includes(value)) return true; + if (typeof prop === "string" && prop.startsWith("acl") && (effectiveAcl !== AclAdmin || ![...Object.values(SharingPermissions), undefined].includes(value))) return true; + // if (typeof prop === "string" && prop.startsWith("acl") && !["Can Edit", "Can Add", "Can View", "Not Shared", undefined].includes(value)) return true; if (typeof prop === "string" && prop !== "__id" && prop !== "__fields" && (prop.startsWith("_") || layoutProps.includes(prop))) { if (!prop.startsWith("_")) { -- cgit v1.2.3-70-g09d2 From 4c5ca565ab3018e5c638d4965475d84750d13ce9 Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 18 Sep 2020 14:19:35 -0400 Subject: prevented inifinite recursion in distributeAcls --- src/fields/util.ts | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'src/fields') diff --git a/src/fields/util.ts b/src/fields/util.ts index 00e1683bd..159a098cf 100644 --- a/src/fields/util.ts +++ b/src/fields/util.ts @@ -204,7 +204,10 @@ export function GetEffectiveAcl(target: any, in_prop?: string | symbol | number, * @param inheritingFromCollection whether the target is being assigned rights after being dragged into a collection (and so is inheriting the acls from the collection) * inheritingFromCollection is not currently being used but could be used if acl assignment defaults change */ -export function distributeAcls(key: string, acl: SharingPermissions, target: Doc, inheritingFromCollection?: boolean) { +export function distributeAcls(key: string, acl: SharingPermissions, target: Doc, inheritingFromCollection?: boolean, visited?: Doc[]) { + if (!visited) visited = [] as Doc[]; + if (visited.includes(target)) return; + visited.push(target); const HierarchyMapping = new Map([ ["Not Shared", 0], @@ -232,29 +235,29 @@ export function distributeAcls(key: string, acl: SharingPermissions, target: Doc const aliases = DocListCast(dataDoc.aliases); if (aliases.length) { aliases.map(alias => { - alias !== target && distributeAcls(key, acl, alias, inheritingFromCollection); + alias !== target && distributeAcls(key, acl, alias, inheritingFromCollection, visited); }); } // maps over the children of the document DocListCast(dataDoc[Doc.LayoutFieldKey(dataDoc)]).map(d => { if (GetEffectiveAcl(d) === AclAdmin && (!inheritingFromCollection || !d[key] || HierarchyMapping.get(StrCast(d[key]))! > HierarchyMapping.get(acl)!)) { - distributeAcls(key, acl, d, inheritingFromCollection); + distributeAcls(key, acl, d, inheritingFromCollection, visited); } const data = d[DataSym]; if (data && GetEffectiveAcl(data) === AclAdmin && (!inheritingFromCollection || !data[key] || HierarchyMapping.get(StrCast(data[key]))! > HierarchyMapping.get(acl)!)) { - distributeAcls(key, acl, data, inheritingFromCollection); + distributeAcls(key, acl, data, inheritingFromCollection, visited); } }); // maps over the annotations of the document DocListCast(dataDoc[Doc.LayoutFieldKey(dataDoc) + "-annotations"]).map(d => { if (GetEffectiveAcl(d) === AclAdmin && (!inheritingFromCollection || !d[key] || HierarchyMapping.get(StrCast(d[key]))! > HierarchyMapping.get(acl)!)) { - distributeAcls(key, acl, d, inheritingFromCollection); + distributeAcls(key, acl, d, inheritingFromCollection, visited); } const data = d[DataSym]; if (data && GetEffectiveAcl(data) === AclAdmin && (!inheritingFromCollection || !data[key] || HierarchyMapping.get(StrCast(data[key]))! > HierarchyMapping.get(acl)!)) { - distributeAcls(key, acl, data, inheritingFromCollection); + distributeAcls(key, acl, data, inheritingFromCollection, visited); } }); } -- cgit v1.2.3-70-g09d2 From feebbe1a82e3dcff22502f635b67df55c90502b3 Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 18 Sep 2020 16:53:30 -0400 Subject: added maximum height to stacking items in sidebar using childLimitHeight. made stacking items non-interactive using contentsPointerEvents. made all links pubilc for now. --- src/client/documents/Documents.ts | 6 +++++- src/client/util/CurrentUserUtils.ts | 4 ++-- src/client/views/DocumentDecorations.tsx | 8 ++++---- src/client/views/collections/CollectionStackingView.tsx | 6 ++++-- src/client/views/nodes/ContentFittingDocumentView.tsx | 8 ++------ src/client/views/nodes/DocumentView.tsx | 16 ++++++++-------- .../views/nodes/formattedText/FormattedTextBox.tsx | 2 +- src/fields/util.ts | 8 ++------ 8 files changed, 28 insertions(+), 30 deletions(-) (limited to 'src/fields') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index f9e3add84..f7ab955f3 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -1,7 +1,7 @@ import { runInAction } from "mobx"; import { basename, extname } from "path"; import { DateField } from "../../fields/DateField"; -import { Doc, DocListCast, DocListCastAsync, Field, HeightSym, Opt, WidthSym } from "../../fields/Doc"; +import { Doc, DocListCast, DocListCastAsync, Field, HeightSym, Opt, WidthSym, AclAddonly } from "../../fields/Doc"; import { HtmlField } from "../../fields/HtmlField"; import { InkField } from "../../fields/InkField"; import { List } from "../../fields/List"; @@ -51,6 +51,7 @@ import { SearchBox } from "../views/search/SearchBox"; import { DashWebRTCVideo } from "../views/webcam/DashWebRTCVideo"; import { DocumentType } from "./DocumentTypes"; import { FilterBox } from "../views/nodes/FilterBox"; +import { SharingPermissions } from "../../fields/util"; const path = require('path'); const defaultNativeImageDim = Number(DFLT_IMAGE_NATIVE_DIM.replace("px", "")); @@ -110,6 +111,8 @@ export interface DocumentOptions { _viewScale?: number; forceActive?: boolean; layout?: string | Doc; // default layout string for a document + contentPointerEvents?: string; // pointer events allowed for content of a document view. eg. set to "none" sidebar views that are intended to document "menus" + childLimitHeight?: number; // whether to limit the height of colleciton children. 0 - means height can be no bigger than width childLayoutTemplate?: Doc; // template for collection to use to render its children (see PresBox or Buxton layout in tree view) childLayoutString?: string; // template string for collection to use to render its children hideLinkButton?: boolean; // whether the blue link counter button should be hidden @@ -980,6 +983,7 @@ export namespace DocUtils { Doc.GetProto(linkDoc)["anchor2-useLinkSmallAnchor"] = target.doc.useLinkSmallAnchor; linkDoc.linkDisplay = true; linkDoc.hidden = true; + Doc.GetProto(linkDoc)["acl-Public"] = linkDoc["acl-Public"] = SharingPermissions.Add; linkDoc.layout_linkView = Cast(Cast(Doc.UserDoc()["template-button-link"], Doc, null).dragFactory, Doc, null); Doc.GetProto(linkDoc).title = ComputedField.MakeFunction('self.anchor1?.title +" (" + (self.linkRelationship||"to") +") " + self.anchor2?.title'); diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index c9c369fba..1e054e5a4 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -871,7 +871,7 @@ export class CurrentUserUtils { // Sharing sidebar is where shared documents are contained static setupSharingSidebar(doc: Doc) { if (doc.mySharedDocs === undefined) { - doc.mySharedDocs = new PrefetchProxy(Docs.Create.StackingDocument([], { title: "My SharedDocs", childDropAction: "alias", system: true, _yMargin: 50, _gridGap: 15, _showTitle: "title", ignoreClick: true, lockedPosition: true })); + doc.mySharedDocs = new PrefetchProxy(Docs.Create.StackingDocument([], { title: "My SharedDocs", childDropAction: "alias", system: true, contentPointerEvents: "none", childLimitHeight: 0, _yMargin: 50, _gridGap: 15, _showTitle: "title", ignoreClick: true, lockedPosition: true })); } } @@ -879,7 +879,7 @@ export class CurrentUserUtils { static setupImportSidebar(doc: Doc) { if (doc.myImportDocs === undefined) { doc.myImportDocs = new PrefetchProxy(Docs.Create.StackingDocument([], { - title: "My ImportDocuments", forceActive: true, ignoreClick: true, _showTitle: "title", _stayInCollection: true, _hideContextMenu: true, + title: "My ImportDocuments", forceActive: true, ignoreClick: true, _showTitle: "title", _stayInCollection: true, _hideContextMenu: true, childLimitHeight: 0, childDropAction: "alias", _autoHeight: true, _yMargin: 50, _gridGap: 15, lockedPosition: true, _chromeStatus: "disabled", system: true })); } diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 108b896a5..257ddc302 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -171,19 +171,19 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> if (e.button === 0) { const selectedDocs = SelectionManager.SelectedDocuments(); if (selectedDocs.length) { - if (e.ctrlKey) { + if (e.ctrlKey) { // open an alias in a new tab with Ctrl Key const alias = Doc.MakeAlias(selectedDocs[0].props.Document); alias.context = undefined; //CollectionDockingView.Instance?.OpenFullScreen(selectedDocs[0]); CollectionDockingView.AddSplit(alias, "right"); - } else if (e.shiftKey) { + } else if (e.shiftKey) { // open centered in a new workspace with Shift Key const alias = Doc.MakeAlias(selectedDocs[0].props.Document); alias.context = undefined; alias.x = -alias[WidthSym]() / 2; alias.y = -alias[HeightSym]() / 2; //CollectionDockingView.Instance?.OpenFullScreen(selectedDocs[0]); CollectionDockingView.AddSplit(Docs.Create.FreeformDocument([alias], { title: "Tab for " + alias.title }), "right"); - } else { + } else { // open same document in new tab CollectionDockingView.ToggleSplit(selectedDocs[0].props.Document, "right"); } } @@ -589,7 +589,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> ); - const openIcon = !canOpen ? (null) : Open In a New Pane} placement="top">
{ e.preventDefault(); e.stopPropagation(); }} onPointerDown={this.onMaximizeDown}> + const openIcon = !canOpen ? (null) : Open in Tab (ctrl: as alias, shift: in new collection)
} placement="top">
{ e.preventDefault(); e.stopPropagation(); }} onPointerDown={this.onMaximizeDown}> {SelectionManager.SelectedDocuments().length === 1 ? : "..."}
; diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 9c9dad2c9..8b2a30b12 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -215,6 +215,7 @@ export class CollectionStackingView extends CollectionSubView(StackingDocument) addDocument={this.props.addDocument} moveDocument={this.props.moveDocument} removeDocument={this.props.removeDocument} + contentsPointerEvents={StrCast(this.layoutDoc.contentPointerEvents)} parentActive={this.props.active} whenActiveChanged={this.props.whenActiveChanged} addDocTab={this.addDocTab} @@ -239,15 +240,16 @@ export class CollectionStackingView extends CollectionSubView(StackingDocument) const nw = NumCast(layoutDoc._nativeWidth) || NumCast(dataDoc?.[`${layoutField}-nativeWidth`]); const nh = NumCast(layoutDoc._nativeHeight) || NumCast(dataDoc?.[`${layoutField}-nativeHeight`]); let wid = this.columnWidth / (this.isStackingView ? this.numGroupColumns : 1); + const hllimit = NumCast(this.layoutDoc.childLimitHeight, -1); if (!layoutDoc._fitWidth && nw && nh) { const aspect = nw && nh ? nh / nw : 1; if (!(this.layoutDoc._columnsFill)) wid = Math.min(this.getDocWidth(d), wid); - return wid * aspect; + return Math.min(hllimit === 0 ? this.props.PanelWidth() : hllimit === -1 ? 10000 : hllimit, wid * aspect); } return layoutDoc._fitWidth ? (!nh ? this.props.PanelHeight() - 2 * this.yMargin : Math.min(wid * nh / (nw || 1), this.layoutDoc._autoHeight ? 100000 : this.props.PanelHeight() - 2 * this.yMargin)) : - Math.max(20, layoutDoc[HeightSym]()); + Math.min(hllimit === 0 ? this.props.PanelWidth() : hllimit === -1 ? 10000 : hllimit, Math.max(20, layoutDoc[HeightSym]())); } columnDividerDown = (e: React.PointerEvent) => { diff --git a/src/client/views/nodes/ContentFittingDocumentView.tsx b/src/client/views/nodes/ContentFittingDocumentView.tsx index 75648f9fd..09051da78 100644 --- a/src/client/views/nodes/ContentFittingDocumentView.tsx +++ b/src/client/views/nodes/ContentFittingDocumentView.tsx @@ -1,14 +1,10 @@ import React = require("react"); import { computed } from "mobx"; import { observer } from "mobx-react"; -import { Transform } from "nodemailer/lib/xoauth2"; -import { Doc, HeightSym, Opt, WidthSym } from "../../../fields/Doc"; -import { ScriptField } from "../../../fields/ScriptField"; +import { Doc, HeightSym, WidthSym } from "../../../fields/Doc"; import { Cast, NumCast, StrCast } from "../../../fields/Types"; import { TraceMobx } from "../../../fields/util"; -import { emptyFunction, returnVal, OmitKeys } from "../../../Utils"; -import { dropActionType } from "../../util/DragManager"; -import { CollectionView } from "../collections/CollectionView"; +import { emptyFunction, OmitKeys, returnVal } from "../../../Utils"; import { DocumentView, DocumentViewProps } from "../nodes/DocumentView"; import "./ContentFittingDocumentView.scss"; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 68328ea4b..ff5c4d1e9 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -80,6 +80,7 @@ export interface DocumentViewProps { PanelWidth: () => number; PanelHeight: () => number; pointerEvents?: string; + contentsPointerEvents?: string; focus: (doc: Doc, willZoom: boolean, scale?: number, afterFocus?: DocFocusFunc) => void; parentActive: (outsideReaction: boolean) => boolean; whenActiveChanged: (isActive: boolean) => void; @@ -892,11 +893,11 @@ export class DocumentView extends DocComponent(Docu isSelected = (outsideReaction?: boolean) => SelectionManager.IsSelected(this, outsideReaction); select = (ctrlPressed: boolean) => { SelectionManager.SelectDoc(this, ctrlPressed); }; - chromeHeight = () => { - const excluded = ["PresBox", "FormattedTextBox", "FontIconBox"]; - const showTextTitle = this.ShowTitle && !excluded.includes(StrCast(this.layoutDoc.layout)) ? this.ShowTitle : undefined; - return showTextTitle ? 25 : 1; + @computed get showOverlappingTitle() { + const excluded = ["PresBox", /* "FormattedTextBox", */ "FontIconBox"]; // bcz: shifting the title for texst causes problems with collaborative use when some people see titles, and others don't + return this.ShowTitle && !excluded.includes(StrCast(this.layoutDoc.layout)) ? this.ShowTitle : undefined; } + chromeHeight = () => this.showOverlappingTitle ? 1 : 25; @computed get finalLayoutKey() { if (typeof this.props.layoutKey === "string") { @@ -913,7 +914,7 @@ export class DocumentView extends DocComponent(Docu @computed get contents() { const pos = this.props.relative ? "relative " : "absolute"; TraceMobx(); - return (
+ return (
(Docu const showTitleHover = StrCast(this.layoutDoc._showTitleHover); const showCaption = StrCast(this.layoutDoc._showCaption); - const showTextTitle = this.ShowTitle && this.rootDoc.type === DocumentType.RTF ? this.ShowTitle : undefined; const captionView = (!showCaption ? (null) :
(Docu
); const titleView = (!this.ShowTitle ? (null) :
users.user.email === this.dataDoc.author)?.userColor || (this.rootDoc.type === DocumentType.RTF ? StrCast(Doc.UserDoc().userColor) : "rgba(0,0,0,0.4)"), pointerEvents: this.onClickHandler || this.Document.ignoreClick ? "none" : undefined, }}> @@ -1054,7 +1054,7 @@ export class DocumentView extends DocComponent(Docu return !this.ShowTitle && !showCaption ? this.contents :
- {this.Document.type !== DocumentType.RTF ? <> {this.contents} {titleView} : <> {titleView} {this.contents} } + {this.showOverlappingTitle ? <> {this.contents} {titleView} : <> {titleView} {this.contents} } {captionView}
; } diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index dc0fafd24..771b6bbbe 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -949,7 +949,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp pos => this._scrollRef.current && this._scrollRef.current.scrollTo({ top: pos }), { fireImmediately: true } ); - setTimeout(() => this.tryUpdateHeight(NumCast(this.layoutDoc.limitHeight, 0))); + setTimeout(() => this.tryUpdateHeight(NumCast(this.layoutDoc.limitHeight))); } pushToGoogleDoc = async () => { diff --git a/src/fields/util.ts b/src/fields/util.ts index 159a098cf..9db79ced1 100644 --- a/src/fields/util.ts +++ b/src/fields/util.ts @@ -232,12 +232,8 @@ export function distributeAcls(key: string, acl: SharingPermissions, target: Doc dataDocChanged = true; // maps over the aliases of the document - const aliases = DocListCast(dataDoc.aliases); - if (aliases.length) { - aliases.map(alias => { - alias !== target && distributeAcls(key, acl, alias, inheritingFromCollection, visited); - }); - } + const links = DocListCast(dataDoc.links); + links.forEach(alias => distributeAcls(key, acl, alias, inheritingFromCollection, visited)); // maps over the children of the document DocListCast(dataDoc[Doc.LayoutFieldKey(dataDoc)]).map(d => { -- cgit v1.2.3-70-g09d2