aboutsummaryrefslogtreecommitdiff
path: root/src/new_fields
diff options
context:
space:
mode:
Diffstat (limited to 'src/new_fields')
-rw-r--r--src/new_fields/Doc.ts73
-rw-r--r--src/new_fields/SchemaHeaderField.ts14
-rw-r--r--src/new_fields/Types.ts4
-rw-r--r--src/new_fields/util.ts38
4 files changed, 81 insertions, 48 deletions
diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts
index 87e048140..d634cf57f 100644
--- a/src/new_fields/Doc.ts
+++ b/src/new_fields/Doc.ts
@@ -1,4 +1,4 @@
-import { observable, action, runInAction } from "mobx";
+import { observable, action, runInAction, ObservableMap } from "mobx";
import { serializable, primitive, map, alias, list, PropSchema, custom } from "serializr";
import { autoObject, SerializationHelper, Deserializable, afterDocDeserialize } from "../client/util/SerializationHelper";
import { DocServer } from "../client/DocServer";
@@ -7,12 +7,13 @@ import { Cast, ToConstructor, PromiseValue, FieldValue, NumCast, BoolCast, StrCa
import { listSpec } from "./Schema";
import { ObjectField } from "./ObjectField";
import { RefField, FieldId } from "./RefField";
-import { ToScriptString, SelfProxy, Parent, OnUpdate, Self, HandleUpdate, Update, Id } from "./FieldSymbols";
+import { ToScriptString, SelfProxy, Parent, OnUpdate, Self, HandleUpdate, Update, Id, Copy } from "./FieldSymbols";
import { scriptingGlobal, CompileScript, Scripting } from "../client/util/Scripting";
import { List } from "./List";
import { DocumentType } from "../client/documents/Documents";
import { ComputedField, ScriptField } from "./ScriptField";
import { PrefetchProxy, ProxyField } from "./Proxy";
+import { CurrentUserUtils } from "../server/authentication/models/current_user_utils";
export namespace Field {
export function toKeyValueString(doc: Doc, key: string): string {
@@ -68,6 +69,7 @@ export function DocListCast(field: FieldResult): Doc[] {
export const WidthSym = Symbol("Width");
export const HeightSym = Symbol("Height");
+export const UpdatingFromServer = Symbol("UpdatingFromServer");
const CachedUpdates = Symbol("Cached updates");
function fetchProto(doc: Doc) {
@@ -77,8 +79,6 @@ function fetchProto(doc: Doc) {
}
}
-let updatingFromServer = false;
-
@scriptingGlobal
@Deserializable("Doc", fetchProto).withFields(["id"])
export class Doc extends RefField {
@@ -132,8 +132,10 @@ export class Doc extends RefField {
//{ [key: string]: Field | FieldWaiting | undefined }
private ___fields: any = {};
+ private [UpdatingFromServer]: boolean = false;
+
private [Update] = (diff: any) => {
- if (updatingFromServer) {
+ if (this[UpdatingFromServer]) {
return;
}
DocServer.UpdateField(this[Id], diff);
@@ -152,6 +154,7 @@ export class Doc extends RefField {
public async [HandleUpdate](diff: any) {
const set = diff.$set;
+ const sameAuthor = this.author === CurrentUserUtils.email;
if (set) {
for (const key in set) {
if (!key.startsWith("fields.")) {
@@ -160,14 +163,15 @@ export class Doc extends RefField {
const fKey = key.substring(7);
const fn = async () => {
const value = await SerializationHelper.Deserialize(set[key]);
- updatingFromServer = true;
+ this[UpdatingFromServer] = true;
this[fKey] = value;
- updatingFromServer = false;
+ this[UpdatingFromServer] = false;
};
- if (DocServer.getFieldWriteMode(fKey)) {
- this[CachedUpdates][fKey] = fn;
- } else {
+ if (sameAuthor || DocServer.getFieldWriteMode(fKey) !== DocServer.WriteMode.Playground) {
+ delete this[CachedUpdates][fKey];
await fn();
+ } else {
+ this[CachedUpdates][fKey] = fn;
}
}
}
@@ -179,14 +183,15 @@ export class Doc extends RefField {
}
const fKey = key.substring(7);
const fn = () => {
- updatingFromServer = true;
+ this[UpdatingFromServer] = true;
delete this[fKey];
- updatingFromServer = false;
+ this[UpdatingFromServer] = false;
};
- if (DocServer.getFieldWriteMode(fKey)) {
- this[CachedUpdates][fKey] = fn;
- } else {
+ if (sameAuthor || DocServer.getFieldWriteMode(fKey) !== DocServer.WriteMode.Playground) {
+ delete this[CachedUpdates][fKey];
await fn();
+ } else {
+ this[CachedUpdates][fKey] = fn;
}
}
}
@@ -214,9 +219,9 @@ export namespace Doc {
export function AddCachedUpdate(doc: Doc, field: string, oldValue: any) {
const val = oldValue;
doc[CachedUpdates][field] = () => {
- updatingFromServer = true;
+ doc[UpdatingFromServer] = true;
doc[field] = val;
- updatingFromServer = false;
+ doc[UpdatingFromServer] = false;
};
}
export function MakeReadOnly(): { end(): void } {
@@ -305,6 +310,10 @@ export namespace Doc {
export function GetProto(doc: Doc) {
return Doc.GetT(doc, "isPrototype", "boolean", true) ? doc : (doc.proto || doc);
}
+ export function GetDataDoc(doc: Doc): Doc {
+ let proto = Doc.GetProto(doc);
+ return proto === doc ? proto : Doc.GetDataDoc(proto);
+ }
export function allKeys(doc: Doc): string[] {
const results: Set<string> = new Set;
@@ -379,7 +388,7 @@ export namespace Doc {
docExtensionForField.extendsDoc = doc; // this is used by search to map field matches on the extension doc back to the document it extends.
docExtensionForField.type = DocumentType.EXTENSION;
let proto: Doc | undefined = doc;
- while (proto && !Doc.IsPrototype(proto)) {
+ while (proto && !Doc.IsPrototype(proto) && proto.proto) {
proto = proto.proto;
}
(proto ? proto : doc)[fieldKey + "_ext"] = new PrefetchProxy(docExtensionForField);
@@ -450,7 +459,7 @@ export namespace Doc {
export function GetLayoutDataDocPair(doc: Doc, dataDoc: Doc | undefined, fieldKey: string, childDocLayout: Doc) {
let layoutDoc = childDocLayout;
- let resolvedDataDoc = !doc.isTemplate && dataDoc !== doc ? dataDoc : undefined;
+ let resolvedDataDoc = !doc.isTemplate && dataDoc !== doc && dataDoc ? Doc.GetDataDoc(dataDoc) : undefined;
if (resolvedDataDoc && Doc.WillExpandTemplateLayout(childDocLayout, resolvedDataDoc)) {
Doc.UpdateDocumentExtensionForField(resolvedDataDoc, fieldKey);
let fieldExtensionDoc = Doc.resolvedFieldDataDoc(resolvedDataDoc, StrCast(childDocLayout.templateField, StrCast(childDocLayout.title)), "dummy");
@@ -498,7 +507,8 @@ export namespace Doc {
let _applyCount: number = 0;
export function ApplyTemplate(templateDoc: Doc) {
if (!templateDoc) return undefined;
- let otherdoc = new Doc();
+ let datadoc = new Doc();
+ let otherdoc = Doc.MakeDelegate(datadoc);
otherdoc.width = templateDoc[WidthSym]();
otherdoc.height = templateDoc[HeightSym]();
otherdoc.title = templateDoc.title + "(..." + _applyCount++ + ")";
@@ -506,6 +516,8 @@ export namespace Doc {
otherdoc.miniLayout = StrCast(templateDoc.miniLayout);
otherdoc.detailedLayout = otherdoc.layout;
otherdoc.type = DocumentType.TEMPLATE;
+ !templateDoc.nativeWidth && (otherdoc.nativeWidth = 0);
+ !templateDoc.nativeHeight && (otherdoc.nativeHeight = 0);
return otherdoc;
}
export function ApplyTemplateTo(templateDoc: Doc, target: Doc, targetData?: Doc) {
@@ -514,6 +526,7 @@ export namespace Doc {
target.nativeHeight = Doc.GetProto(target).nativeHeight = undefined;
target.width = templateDoc.width;
target.height = templateDoc.height;
+ target.onClick = templateDoc.onClick instanceof ObjectField && templateDoc.onClick[Copy]();
Doc.GetProto(target).type = DocumentType.TEMPLATE;
if (targetData && targetData.layout === target) {
targetData.layout = temp;
@@ -524,6 +537,8 @@ export namespace Doc {
target.miniLayout = StrCast(templateDoc.miniLayout);
target.detailedLayout = target.layout;
}
+ !templateDoc.nativeWidth && (target.nativeWidth = 0);
+ !templateDoc.nativeHeight && (target.nativeHeight = 0);
}
export function MakeTemplate(fieldTemplate: Doc, metaKey: string, templateDataDoc: Doc) {
@@ -581,23 +596,23 @@ export namespace Doc {
}
export class DocBrush {
- @observable BrushedDoc: Doc[] = [];
+ @observable BrushedDoc: ObservableMap<Doc, boolean> = new ObservableMap();
}
const manager = new DocBrush();
export function IsBrushed(doc: Doc) {
- return manager.BrushedDoc.some(d => Doc.AreProtosEqual(d, doc));
+ return manager.BrushedDoc.has(doc) || manager.BrushedDoc.has(Doc.GetDataDoc(doc));
}
export function IsBrushedDegree(doc: Doc) {
- return manager.BrushedDoc.some(d => d === doc) ? 2 : Doc.IsBrushed(doc) ? 1 : 0;
+ return manager.BrushedDoc.has(Doc.GetDataDoc(doc)) ? 2 : manager.BrushedDoc.has(doc) ? 1 : 0;
}
export function BrushDoc(doc: Doc) {
- if (manager.BrushedDoc.indexOf(doc) === -1) runInAction(() => manager.BrushedDoc.push(doc));
+ manager.BrushedDoc.set(doc, true);
+ manager.BrushedDoc.set(Doc.GetDataDoc(doc), true);
}
export function UnBrushDoc(doc: Doc) {
- let index = manager.BrushedDoc.indexOf(doc);
- if (index !== -1) runInAction(() => manager.BrushedDoc.splice(index, 1));
+ manager.BrushedDoc.delete(doc);
+ manager.BrushedDoc.delete(Doc.GetDataDoc(doc));
}
}
-Scripting.addGlobal(function renameAlias(doc: any, n: any) {
- return StrCast(doc.title).replace(/\([0-9]*\)/, "") + `(${n})`;
-}); \ No newline at end of file
+Scripting.addGlobal(function renameAlias(doc: any, n: any) { return StrCast(doc.title).replace(/\([0-9]*\)/, "") + `(${n})`; });
+Scripting.addGlobal(function getProto(doc: any) { return Doc.GetProto(doc); }); \ No newline at end of file
diff --git a/src/new_fields/SchemaHeaderField.ts b/src/new_fields/SchemaHeaderField.ts
index 23605cfb0..7494c9bd1 100644
--- a/src/new_fields/SchemaHeaderField.ts
+++ b/src/new_fields/SchemaHeaderField.ts
@@ -1,8 +1,8 @@
import { Deserializable } from "../client/util/SerializationHelper";
-import { serializable, createSimpleSchema, primitive } from "serializr";
+import { serializable, primitive } from "serializr";
import { ObjectField } from "./ObjectField";
import { Copy, ToScriptString, OnUpdate } from "./FieldSymbols";
-import { scriptingGlobal, Scripting } from "../client/util/Scripting";
+import { scriptingGlobal } from "../client/util/Scripting";
import { ColumnType } from "../client/views/collections/CollectionSchemaView";
export const PastelSchemaPalette = new Map<string, string>([
@@ -53,9 +53,11 @@ export class SchemaHeaderField extends ObjectField {
@serializable(primitive())
width: number;
@serializable(primitive())
+ collapsed: boolean | undefined;
+ @serializable(primitive())
desc: boolean | undefined; // boolean determines sort order, undefined when no sort
- constructor(heading: string = "", color: string = RandomPastel(), type?: ColumnType, width?: number, desc?: boolean) {
+ constructor(heading: string = "", color: string = RandomPastel(), type?: ColumnType, width?: number, desc?: boolean, collapsed?: boolean) {
super();
this.heading = heading;
@@ -63,6 +65,7 @@ export class SchemaHeaderField extends ObjectField {
this.type = type ? type : 0;
this.width = width ? width : -1;
this.desc = desc;
+ this.collapsed = collapsed;
}
setHeading(heading: string) {
@@ -90,6 +93,11 @@ export class SchemaHeaderField extends ObjectField {
this[OnUpdate]();
}
+ setCollapsed(collapsed: boolean | undefined) {
+ this.collapsed = collapsed;
+ this[OnUpdate]();
+ }
+
[Copy]() {
return new SchemaHeaderField(this.heading, this.color, this.type);
}
diff --git a/src/new_fields/Types.ts b/src/new_fields/Types.ts
index 09cbff25e..0ca35fab2 100644
--- a/src/new_fields/Types.ts
+++ b/src/new_fields/Types.ts
@@ -2,6 +2,7 @@ import { Field, Opt, FieldResult, Doc } from "./Doc";
import { List } from "./List";
import { RefField } from "./RefField";
import { DateField } from "./DateField";
+import { ScriptField } from "./ScriptField";
export type ToType<T extends InterfaceValue> =
T extends "string" ? string :
@@ -86,6 +87,9 @@ export function BoolCast(field: FieldResult, defaultVal: boolean | null = false)
export function DateCast(field: FieldResult) {
return Cast(field, DateField, null);
}
+export function ScriptCast(field: FieldResult) {
+ return Cast(field, ScriptField, null);
+}
type WithoutList<T extends Field> = T extends List<infer R> ? (R extends RefField ? (R | Promise<R>)[] : R[]) : T;
diff --git a/src/new_fields/util.ts b/src/new_fields/util.ts
index 6c05da507..c546e2aac 100644
--- a/src/new_fields/util.ts
+++ b/src/new_fields/util.ts
@@ -1,5 +1,5 @@
import { UndoManager } from "../client/util/UndoManager";
-import { Doc, Field, FieldResult } from "./Doc";
+import { Doc, Field, FieldResult, UpdatingFromServer } from "./Doc";
import { SerializationHelper } from "../client/util/SerializationHelper";
import { ProxyField } from "./Proxy";
import { RefField } from "./RefField";
@@ -59,23 +59,29 @@ const _setterImpl = action(function (target: any, prop: string | symbol | number
delete curValue[Parent];
delete curValue[OnUpdate];
}
- if (value === undefined) {
- delete target.__fields[prop];
- } else {
- target.__fields[prop] = value;
- }
const writeMode = DocServer.getFieldWriteMode(prop as string);
- if (typeof value === "object" && !(value instanceof ObjectField)) debugger;
- if (!writeMode || (writeMode === DocServer.WriteMode.SameUser && receiver.author === CurrentUserUtils.email)) {
- if (value === undefined) target[Update]({ '$unset': { ["fields." + prop]: "" } });
- else target[Update]({ '$set': { ["fields." + prop]: value instanceof ObjectField ? SerializationHelper.Serialize(value) : (value === undefined ? null : value) } });
- } else {
- DocServer.registerDocWithCachedUpdate(receiver, prop as string, curValue);
+ const fromServer = target[UpdatingFromServer];
+ const sameAuthor = fromServer || (receiver.author === CurrentUserUtils.email);
+ const writeToDoc = sameAuthor || (writeMode !== DocServer.WriteMode.LiveReadonly);
+ const writeToServer = sameAuthor || (writeMode === DocServer.WriteMode.Default);
+ if (writeToDoc) {
+ if (value === undefined) {
+ delete target.__fields[prop];
+ } else {
+ target.__fields[prop] = value;
+ }
+ if (typeof value === "object" && !(value instanceof ObjectField)) debugger;
+ if (writeToServer) {
+ if (value === undefined) target[Update]({ '$unset': { ["fields." + prop]: "" } });
+ else target[Update]({ '$set': { ["fields." + prop]: value instanceof ObjectField ? SerializationHelper.Serialize(value) : (value === undefined ? null : value) } });
+ } else {
+ DocServer.registerDocWithCachedUpdate(receiver, prop as string, curValue);
+ }
+ UndoManager.AddEvent({
+ redo: () => receiver[prop] = value,
+ undo: () => receiver[prop] = curValue
+ });
}
- UndoManager.AddEvent({
- redo: () => receiver[prop] = value,
- undo: () => receiver[prop] = curValue
- });
return true;
});