import { Deserializable, autoObject } from "../client/util/SerializationHelper"; import { Field, Update, Self } from "./Doc"; import { setter, getter } from "./util"; import { serializable, alias, list } from "serializr"; import { observable, observe, IArrayChange, IArraySplice, IObservableArray, Lambda } from "mobx"; import { ObjectField, OnUpdate } from "./ObjectField"; const listHandlers: any = { push(...items: any[]) { console.log("push"); console.log(...items); return this[Self].__fields.push(...items); }, pop(): any { return this[Self].__fields.pop(); } }; function listGetter(target: any, prop: string | number | symbol, receiver: any): any { if (listHandlers.hasOwnProperty(prop)) { return listHandlers[prop]; } return getter(target, prop, receiver); } interface ListSpliceUpdate { type: "splice"; index: number; added: T[]; removedCount: number; } interface ListIndexUpdate { type: "update"; index: number; newValue: T; } type ListUpdate = ListSpliceUpdate | ListIndexUpdate; const ObserveDisposer = Symbol("Observe Disposer"); function listObserver(this: ListImpl, change: IArrayChange | IArraySplice) { if (change.type === "splice") { this[Update]({ index: change.index, removedCount: change.removedCount, added: change.added, type: change.type }); } else { //This should already be handled by the getter for the Proxy // this[Update]({ // index: change.index, // newValue: change.newValue, // type: change.type // }); } } @Deserializable("list") class ListImpl extends ObjectField { constructor(fields: T[] = []) { super(); this.__fields = fields; this[ObserveDisposer] = observe(this.__fields as IObservableArray, listObserver.bind(this)); const list = new Proxy(this, { set: setter, get: getter, deleteProperty: () => { throw new Error("Currently properties can't be deleted from documents, assign to undefined instead"); }, defineProperty: () => { throw new Error("Currently properties can't be defined on documents using Object.defineProperty"); }, }); return list; } [key: number]: T | null | undefined; @serializable(alias("fields", list(autoObject()))) @observable private __fields: (T | null | undefined)[]; private [Update] = (diff: any) => { console.log(diff); const update = this[OnUpdate]; update && update(diff); } private [ObserveDisposer]: Lambda; private [Self] = this; } export type List = ListImpl & T[]; export const List: { new (fields?: T[]): List } = ListImpl as any;