aboutsummaryrefslogtreecommitdiff
path: root/src/fields/util.ts
diff options
context:
space:
mode:
authorsrichman333 <sarah_n_richman@brown.edu>2023-06-14 17:23:23 -0400
committersrichman333 <sarah_n_richman@brown.edu>2023-06-14 17:23:23 -0400
commitf0474c18d092f4db49255a1e92d7f052b7398897 (patch)
tree1e26ccaf42dec4d99904e2eddb36dff6f3b55948 /src/fields/util.ts
parent20d217d825891cf29a432a048d1f8e7bc04d062a (diff)
parentbf1198fbe73847087b1ec8e00a43306816b3508a (diff)
Merge branch 'master' into collaboration-sarah
Diffstat (limited to 'src/fields/util.ts')
-rw-r--r--src/fields/util.ts112
1 files changed, 52 insertions, 60 deletions
diff --git a/src/fields/util.ts b/src/fields/util.ts
index 5e925cd7e..6058a5a5f 100644
--- a/src/fields/util.ts
+++ b/src/fields/util.ts
@@ -9,11 +9,10 @@ import { returnZero } from '../Utils';
import CursorField from './CursorField';
import {
AclAdmin,
- AclAugment,
AclEdit,
aclLevel,
AclPrivate,
- AclReadonly,
+ AclSelfEdit,
AclSym,
DataSym,
Doc,
@@ -35,7 +34,7 @@ import { ObjectField } from './ObjectField';
import { PrefetchProxy, ProxyField } from './Proxy';
import { RefField } from './RefField';
import { SchemaHeaderField } from './SchemaHeaderField';
-import { ComputedField } from './ScriptField';
+import { ComputedField, ScriptField } from './ScriptField';
import { ScriptCast, StrCast } from './Types';
import { convertCompilerOptionsFromJson } from 'typescript';
@@ -57,7 +56,7 @@ const _setterImpl = action(function (target: any, prop: string | symbol | number
if (value !== undefined) {
value = value[SelfProxy] || value;
}
- const curValue = target.__fields[prop];
+ const curValue = target.__fieldTuples[prop];
if (curValue === value || (curValue instanceof ProxyField && value instanceof RefField && curValue.fieldId === value[Id])) {
// TODO This kind of checks correctly in the case that curValue is a ProxyField and value is a RefField, but technically
// curValue should get filled in with value if it isn't already filled in, in case we fetched the referenced field some other way
@@ -66,6 +65,7 @@ const _setterImpl = action(function (target: any, prop: string | symbol | number
if (value instanceof RefField) {
value = new ProxyField(value);
}
+
if (value instanceof ObjectField) {
if (value[Parent] && value[Parent] !== receiver && !(value instanceof PrefetchProxy)) {
throw new Error("Can't put the same object in multiple documents at the same time");
@@ -88,11 +88,13 @@ const _setterImpl = action(function (target: any, prop: string | symbol | number
if (writeToDoc) {
if (value === undefined) {
- target.__fieldKeys && delete target.__fieldKeys[prop];
- delete target.__fields[prop];
+ target[FieldKeys] && delete target[FieldKeys][prop]; // Lists don't have a FieldKeys field
+ delete target.__fieldTuples[prop];
} else {
- target.__fieldKeys && (target.__fieldKeys[prop] = true);
- target.__fields[prop] = value;
+ // bcz: uncomment to see if server is being updated
+ // console.log(prop + ' = ' + value + '(' + curValue + ')');
+ target[FieldKeys] && (target[FieldKeys][prop] = true); // Lists don't have a FieldKeys field
+ target.__fieldTuples[prop] = value;
}
if (writeToServer) {
@@ -103,20 +105,24 @@ const _setterImpl = action(function (target: any, prop: string | symbol | number
DocServer.registerDocWithCachedUpdate(receiver, prop as string, curValue);
}
!receiver[Initializing] &&
+ !receiver.dontUndo &&
(!receiver[UpdatingFromServer] || receiver[ForceServerWrite]) &&
- UndoManager.AddEvent({
- redo: () => (receiver[prop] = value),
- undo: () => {
- const wasUpdate = receiver[UpdatingFromServer];
- const wasForce = receiver[ForceServerWrite];
- receiver[ForceServerWrite] = true; // needed since writes aren't propagated to server if UpdatingFromServerIsSet
- receiver[UpdatingFromServer] = true; // needed if the event caused ACL's to change such that the doc is otherwise no longer editable.
- receiver[prop] = curValue;
- receiver[ForceServerWrite] = wasForce;
- receiver[UpdatingFromServer] = wasUpdate;
+ UndoManager.AddEvent(
+ {
+ redo: () => (receiver[prop] = value),
+ undo: () => {
+ const wasUpdate = receiver[UpdatingFromServer];
+ const wasForce = receiver[ForceServerWrite];
+ receiver[ForceServerWrite] = true; // needed since writes aren't propagated to server if UpdatingFromServerIsSet
+ receiver[UpdatingFromServer] = true; // needed if the event caused ACL's to change such that the doc is otherwise no longer editable.
+ receiver[prop] = curValue;
+ receiver[ForceServerWrite] = wasForce;
+ receiver[UpdatingFromServer] = wasUpdate;
+ },
+ prop: prop?.toString(),
},
- prop: prop?.toString(),
- });
+ value
+ );
return true;
}
return false;
@@ -143,13 +149,13 @@ export function denormalizeEmail(email: string) {
* Copies parent's acl fields to the child
*/
export function inheritParentAcls(parent: Doc, child: Doc) {
+ return;
const dataDoc = parent[DataSym];
for (const key of Object.keys(dataDoc)) {
// if the default acl mode is private, then don't inherit the acl-Public permission, but set it to private.
const permission = key === 'acl-Public' && Doc.defaultAclPrivate ? AclPrivate : dataDoc[key];
key.startsWith('acl') && distributeAcls(key, permission, child);
}
- return;
}
/**
@@ -209,24 +215,8 @@ export function SetCachedGroups(groups: string[]) {
}
function getEffectiveAcl(target: any, user?: string): symbol {
const targetAcls = target[AclSym];
- if (targetAcls?.['acl-Me'] === AclAdmin || GetCachedGroupByName(SharingPermissions.Admin)) return AclAdmin;
- if (target['acl-' + normalizeEmail(Doc.CurrentUserEmail)]) {
- if (target['acl-' + normalizeEmail(Doc.CurrentUserEmail)] == SharingPermissions.Admin) {
- return AclAdmin;
- }
- if (target['acl-' + normalizeEmail(Doc.CurrentUserEmail)] == SharingPermissions.Edit) {
- return AclEdit;
- }
- if (target['acl-' + normalizeEmail(Doc.CurrentUserEmail)] == SharingPermissions.Augment) {
- return AclAugment;
- }
- if (target['acl-' + normalizeEmail(Doc.CurrentUserEmail)] == SharingPermissions.View) {
- return AclReadonly;
- }
- if (target['acl-' + normalizeEmail(Doc.CurrentUserEmail)] == SharingPermissions.None) {
- return AclPrivate;
- }
- }
+ if (targetAcls?.['acl-Me'] === AclAdmin || GetCachedGroupByName('Admin')) return AclAdmin;
+
const userChecked = user || Doc.CurrentUserEmail; // if the current user is the author of the document / the current user is a member of the admin group
if (targetAcls && Object.keys(targetAcls).length) {
let effectiveAcl = AclPrivate;
@@ -248,7 +238,7 @@ function getEffectiveAcl(target: any, user?: string): symbol {
return DocServer?.Control?.isReadOnly?.() && HierarchyMapping.get(effectiveAcl)!.level < aclLevel.editable ? AclEdit : effectiveAcl;
}
// authored documents are private until an ACL is set.
- const targetAuthor = target.__fields?.author || target.author; // target may be a Doc of Proxy, so check __fields.author and .author
+ const targetAuthor = target.__fieldTuples?.author || target.author; // target may be a Doc of Proxy, so check __fieldTuples.author and .author
if (targetAuthor && targetAuthor !== userChecked) return AclPrivate;
return AclAdmin;
let acl = AclPrivate;
@@ -272,7 +262,7 @@ export function distributeAcls(key: string, acl: SharingPermissions, target: Doc
if (!visited) visited = [] as Doc[];
if (!target || visited.includes(target)) return;
- if ((target._viewType === CollectionViewType.Docking && visited.length > 1) || Doc.GetProto(visited[0]) !== Doc.GetProto(target)) {
+ if ((target._type_collection === CollectionViewType.Docking && visited.length > 1) || Doc.GetProto(visited[0]) !== Doc.GetProto(target)) {
target[key] = acl;
Doc.GetProto(target)[key] = acl;
if (target !== Doc.GetProto(target)) {
@@ -296,7 +286,7 @@ export function distributeAcls(key: string, acl: SharingPermissions, target: Doc
}
let dataDocChanged = false;
- const dataDoc = target[DataSym];
+ const dataDoc = target[DocData];
if (dataDoc && (!inheritingFromCollection || !dataDoc[key] || ReverseHierarchyMap.get(StrCast(dataDoc[key]))! > ReverseHierarchyMap.get(acl)!)) {
if (GetEffectiveAcl(dataDoc) === AclAdmin) {
dataDoc[key] = acl;
@@ -309,13 +299,13 @@ export function distributeAcls(key: string, acl: SharingPermissions, target: Doc
// maps over the children of the document
DocListCast(dataDoc[Doc.LayoutFieldKey(dataDoc)]).forEach(d => {
distributeAcls(key, acl, d, inheritingFromCollection, visited);
- distributeAcls(key, acl, d[DataSym], inheritingFromCollection, visited);
+ distributeAcls(key, acl, d[DocData], inheritingFromCollection, visited);
});
// maps over the annotations of the document
- DocListCast(dataDoc[Doc.LayoutFieldKey(dataDoc) + '-annotations']).forEach(d => {
+ DocListCast(dataDoc[Doc.LayoutFieldKey(dataDoc) + '_annotations']).forEach(d => {
distributeAcls(key, acl, d, inheritingFromCollection, visited);
- distributeAcls(key, acl, d[DataSym], inheritingFromCollection, visited);
+ distributeAcls(key, acl, d[DocData], inheritingFromCollection, visited);
});
}
@@ -330,16 +320,16 @@ export function setter(target: any, in_prop: string | symbol | number, value: an
// 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 !== '__id' && prop !== '__fields' && prop.startsWith('_')) {
+ if (typeof prop === 'string' && prop !== '__id' && prop !== '__fieldTuples' && prop.startsWith('_')) {
if (!prop.startsWith('__')) prop = prop.substring(1);
if (target.__LAYOUT__) {
target.__LAYOUT__[prop] = value;
return true;
}
}
- if (target.__fields[prop] instanceof ComputedField) {
- if (target.__fields[prop].setterscript && value !== undefined && !(value instanceof ComputedField)) {
- return ScriptCast(target.__fields[prop])?.setterscript?.run({ self: target[SelfProxy], this: target[SelfProxy], value }).success ? true : false;
+ if (target.__fieldTuples[prop] instanceof ComputedField) {
+ if (target.__fieldTuples[prop].setterscript && value !== undefined && !(value instanceof ComputedField)) {
+ return ScriptCast(target.__fieldTuples[prop])?.setterscript?.run({ self: target[SelfProxy], this: target[SelfProxy], value }).success ? true : false;
}
}
return _setter(target, prop, value, receiver);
@@ -349,14 +339,13 @@ export function getter(target: any, prop: string | symbol, proxy: any): any {
// prettier-ignore
switch (prop) {
case 'then' : return undefined;
- case '__fields' : case '__id':
- case 'constructor': case 'toString': case 'valueOf':
- case 'factory': case 'serializeInfo':
+ case 'constructor': case 'toString': case 'valueOf':
+ case 'serializeInfo': case 'factory':
return target[prop];
- case AclSym : return target[AclSym];
- case $mobx: return target.__fields[prop];
- case LayoutSym: return target.__LAYOUT__;
- case HeightSym: case WidthSym: if (GetEffectiveAcl(target) === AclPrivate) return returnZero;
+ case DocAcl : return target[DocAcl];
+ case $mobx: return target.__fieldTuples[prop];
+ case DocLayout: return target.__LAYOUT__;
+ case Height: case Width: if (GetEffectiveAcl(target) === AclPrivate) return returnZero;
default :
if (typeof prop === 'symbol') return target[prop];
if (prop.startsWith('isMobX')) return target[prop];
@@ -370,7 +359,7 @@ export function getter(target: any, prop: string | symbol, proxy: any): any {
}
function getFieldImpl(target: any, prop: string | number, proxy: any, ignoreProto: boolean = false): any {
- const field = target.__fields[prop];
+ const field = target.__fieldTuples[prop];
const value = field?.[ToValue]?.(proxy); // converts ComputedFields to values, or unpacks ProxyFields into Proxys
if (value) return value.value;
if (field === undefined && !ignoreProto && prop !== 'proto') {
@@ -414,6 +403,7 @@ export function updateFunction(target: any, prop: any, value: any, receiver: any
diff?.op === '$addToSet'
? {
redo: () => {
+ console.log('redo $add: ' + prop, diff.items); // bcz: uncomment to log undo
receiver[prop].push(...diff.items.map((item: any) => item.value ?? item));
lastValue = ObjectField.MakeCopy(receiver[prop]);
},
@@ -430,11 +420,12 @@ export function updateFunction(target: any, prop: any, value: any, receiver: any
});
lastValue = ObjectField.MakeCopy(receiver[prop]);
}),
- prop: '',
+ prop: 'add ' + diff.items.length + ' items to list',
}
: diff?.op === '$remFromSet'
? {
redo: action(() => {
+ console.log('redo $rem: ' + prop, diff.items); // bcz: uncomment to log undo
diff.items.forEach((item: any) => {
const ind = item instanceof SchemaHeaderField ? receiver[prop].findIndex((ele: any) => ele instanceof SchemaHeaderField && ele.heading === item.heading) : receiver[prop].indexOf(item.value ?? item);
ind !== -1 && receiver[prop].splice(ind, 1);
@@ -454,10 +445,11 @@ export function updateFunction(target: any, prop: any, value: any, receiver: any
});
lastValue = ObjectField.MakeCopy(receiver[prop]);
},
- prop: '',
+ prop: 'remove ' + diff.items.length + ' items from list',
}
: {
redo: () => {
+ console.log('redo list: ' + prop, receiver[prop]); // bcz: uncomment to log undo
receiver[prop] = ObjectField.MakeCopy(newValue as List<any>);
lastValue = ObjectField.MakeCopy(receiver[prop]);
},
@@ -466,7 +458,7 @@ export function updateFunction(target: any, prop: any, value: any, receiver: any
receiver[prop] = ObjectField.MakeCopy(prevValue as List<any>);
lastValue = ObjectField.MakeCopy(receiver[prop]);
},
- prop: '',
+ prop: 'assign list',
}
);
}