diff options
18 files changed, 179 insertions, 75 deletions
diff --git a/src/client/northstar/operations/HistogramOperation.ts b/src/client/northstar/operations/HistogramOperation.ts index 5c9c832c0..78b206bdc 100644 --- a/src/client/northstar/operations/HistogramOperation.ts +++ b/src/client/northstar/operations/HistogramOperation.ts @@ -65,7 +65,7 @@ export class HistogramOperation extends BaseOperation implements IBaseFilterCons @computed public get FilterString(): string { if (this.OverridingFilters.length > 0) { - return "(" + this.OverridingFilters.filter(fm => fm != null).map(fm => fm.ToPythonString()).join(" || ") + ")"; + return "(" + this.OverridingFilters.filter(fm => fm !== null).map(fm => fm.ToPythonString()).join(" || ") + ")"; } let filterModels: FilterModel[] = []; return FilterModel.GetFilterModelsRecursive(this, new Set<IBaseFilterProvider>(), filterModels, true); @@ -89,8 +89,9 @@ export class HistogramOperation extends BaseOperation implements IBaseFilterCons @action public DrillDown(up: boolean) { if (!up) { - if (!this.BarFilterModels.length) + if (!this.BarFilterModels.length) { return; + } this._stackedFilters.push(this.BarFilterModels.map(f => f)); this.OverridingFilters.length = 0; this.OverridingFilters.push(...this._stackedFilters[this._stackedFilters.length - 1]); diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index ec192eaff..7fd86ebcd 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -157,9 +157,9 @@ export namespace DragManager { export function StartDocumentDrag(eles: HTMLElement[], dragData: DocumentDragData, downX: number, downY: number, options?: DragOptions) { StartDrag(eles, dragData, downX, downY, options, (dropData: { [id: string]: any }) => - (dropData.droppedDocuments = dragData.userDropAction == "alias" || (!dragData.userDropAction && dragData.dropAction == "alias") ? + (dropData.droppedDocuments = dragData.userDropAction === "alias" || (!dragData.userDropAction && dragData.dropAction === "alias") ? dragData.draggedDocuments.map(d => Doc.MakeAlias(d)) : - dragData.userDropAction == "copy" || (!dragData.userDropAction && dragData.dropAction == "copy") ? + dragData.userDropAction === "copy" || (!dragData.userDropAction && dragData.dropAction === "copy") ? dragData.draggedDocuments.map(d => Doc.MakeCopy(d, true)) : dragData.draggedDocuments)); } @@ -282,7 +282,7 @@ export namespace DragManager { }; let hideDragElements = () => { - dragElements.map(dragElement => dragElement.parentNode == dragDiv && dragDiv.removeChild(dragElement)); + dragElements.map(dragElement => dragElement.parentNode === dragDiv && dragDiv.removeChild(dragElement)); eles.map(ele => (ele.hidden = false)); }; let endDrag = () => { @@ -291,7 +291,7 @@ export namespace DragManager { if (options) { options.handlers.dragComplete({}); } - } + }; AbortDrag = () => { hideDragElements(); diff --git a/src/client/views/PreviewCursor.tsx b/src/client/views/PreviewCursor.tsx index 4ac4b9c95..78024a58c 100644 --- a/src/client/views/PreviewCursor.tsx +++ b/src/client/views/PreviewCursor.tsx @@ -17,7 +17,7 @@ export class PreviewCursor extends React.Component<{}> { constructor(props: any) { super(props); - document.addEventListener("keydown", this.onKeyPress) + document.addEventListener("keydown", this.onKeyPress); } @action @@ -27,7 +27,7 @@ export class PreviewCursor extends React.Component<{}> { // the keyPress here. //if not these keys, make a textbox if preview cursor is active! if (e.key.startsWith("F") && !e.key.endsWith("F")) { - } else if (e.key != "Escape" && e.key != "Alt" && e.key != "Shift" && e.key != "Meta" && e.key != "Control" && !e.defaultPrevented && !(e as any).DASHFormattedTextBoxHandled) { + } else if (e.key !== "Escape" && e.key !== "Alt" && e.key !== "Shift" && e.key !== "Meta" && e.key !== "Control" && !e.defaultPrevented && !(e as any).DASHFormattedTextBoxHandled) { if ((!e.ctrlKey && !e.metaKey) || e.key === "v" || e.key === "q") { PreviewCursor.Visible && PreviewCursor._onKeyPress && PreviewCursor._onKeyPress(e); PreviewCursor.Visible = false; diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index d894909d0..159815ea5 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -392,13 +392,15 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> { get previewPanelCenteringOffset() { return (this._panelWidth - this.nativeWidth() * this.contentScaling()) / 2; } get content() { - if (!this._document) + if (!this._document) { return (null); + } return ( <div className="collectionDockingView-content" ref={this._mainCont} style={{ transform: `translate(${this.previewPanelCenteringOffset}px, 0px)` }}> - <DocumentView key={this._document![Id]} Document={this._document!} + <DocumentView key={this._document[Id]} Document={this._document} toggleMinimized={emptyFunction} + bringToFront={emptyFunction} addDocument={undefined} removeDocument={undefined} ContentScaling={this.contentScaling} diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 828ac880a..232679a59 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -10,13 +10,14 @@ import * as rp from 'request-promise'; import { CollectionView } from "./CollectionView"; import { CollectionPDFView } from "./CollectionPDFView"; import { CollectionVideoView } from "./CollectionVideoView"; -import { Doc, Opt } from "../../../new_fields/Doc"; +import { Doc, Opt, FieldResult } from "../../../new_fields/Doc"; import { DocComponent } from "../DocComponent"; import { listSpec } from "../../../new_fields/Schema"; -import { Cast, PromiseValue, FieldValue } from "../../../new_fields/Types"; +import { Cast, PromiseValue, FieldValue, ListSpec } from "../../../new_fields/Types"; import { List } from "../../../new_fields/List"; import { DocServer } from "../../DocServer"; import { ObjectField } from "../../../new_fields/ObjectField"; +import CursorField, { CursorPosition, CursorMetadata } from "../../../new_fields/CursorField"; export interface CollectionViewProps extends FieldViewProps { addDocument: (document: Doc, allowDuplicates?: boolean) => boolean; @@ -30,8 +31,6 @@ export interface SubCollectionViewProps extends CollectionViewProps { CollectionView: CollectionView | CollectionPDFView | CollectionVideoView; } -export type CursorEntry = TupleField<[string, string], [number, number]>; - export function CollectionSubView<T>(schemaCtor: (doc: Doc) => T) { class CollectionSubView extends DocComponent<SubCollectionViewProps, T>(schemaCtor) { private dropDisposer?: DragManager.DragDropDisposer; @@ -55,25 +54,24 @@ export function CollectionSubView<T>(schemaCtor: (doc: Doc) => T) { @action protected async setCursorPosition(position: [number, number]) { - return; let ind; let doc = this.props.Document; let id = CurrentUserUtils.id; let email = CurrentUserUtils.email; + let pos = { x: position[0], y: position[1] }; if (id && email) { - let textInfo: [string, string] = [id, email]; const proto = await doc.proto; if (!proto) { return; } - let cursors = await Cast(proto.cursors, listSpec(ObjectField)); + let cursors = Cast(proto.cursors, listSpec(CursorField)); if (!cursors) { - proto.cursors = cursors = new List<ObjectField>(); + proto.cursors = cursors = new List<CursorField>(); } - if (cursors.length > 0 && (ind = cursors.findIndex(entry => entry.Data[0][0] === id)) > -1) { - cursors[ind].Data[1] = position; + if (cursors.length > 0 && (ind = cursors.findIndex(entry => entry.data.metadata.id === id)) > -1) { + cursors[ind].setPosition(pos); } else { - let entry = new TupleField<[string, string], [number, number]>([textInfo, position]); + let entry = new CursorField({ metadata: { id: id, identifier: email }, position: pos }); cursors.push(entry); } } diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 6e690236f..33787f06b 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -146,8 +146,8 @@ class TreeView extends React.Component<TreeViewProps> { } } - onPointerEnter = (e: React.PointerEvent): void => { this.props.document.libraryBrush = true; } - onPointerLeave = (e: React.PointerEvent): void => { this.props.document.libraryBrush = false; } + onPointerEnter = (e: React.PointerEvent): void => { this.props.document.libraryBrush = true; }; + onPointerLeave = (e: React.PointerEvent): void => { this.props.document.libraryBrush = false; }; render() { let bulletType = BulletType.List; diff --git a/src/client/views/collections/CollectionVideoView.tsx b/src/client/views/collections/CollectionVideoView.tsx index 9dee217cb..cb3fd1ba4 100644 --- a/src/client/views/collections/CollectionVideoView.tsx +++ b/src/client/views/collections/CollectionVideoView.tsx @@ -90,7 +90,7 @@ export class CollectionVideoView extends React.Component<FieldViewProps> { } } - setVideoBox = (player: VideoBox) => { this._videoBox = player; } + setVideoBox = (player: VideoBox) => { this._videoBox = player; }; private subView = (_type: CollectionViewType, renderProps: CollectionRenderProps) => { let props = { ...this.props, ...renderProps }; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx index 036745eca..642118d75 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx @@ -1,26 +1,35 @@ import { computed } from "mobx"; import { observer } from "mobx-react"; -import { CollectionViewProps, CursorEntry } from "../CollectionSubView"; +import { CollectionViewProps } from "../CollectionSubView"; import "./CollectionFreeFormView.scss"; import React = require("react"); import v5 = require("uuid/v5"); import { CurrentUserUtils } from "../../../../server/authentication/models/current_user_utils"; +import CursorField from "../../../../new_fields/CursorField"; +import { List } from "../../../../new_fields/List"; +import { Cast } from "../../../../new_fields/Types"; +import { listSpec } from "../../../../new_fields/Schema"; @observer export class CollectionFreeFormRemoteCursors extends React.Component<CollectionViewProps> { - protected getCursors(): CursorEntry[] { + + protected getCursors(): CursorField[] { let doc = this.props.Document; + let id = CurrentUserUtils.id; - let cursors = doc.GetList(KeyStore.Cursors, [] as CursorEntry[]); - let notMe = cursors.filter(entry => entry.Data[0][0] !== id); - return id ? notMe : []; + if (!id) { + return []; + } + + let cursors = Cast(doc.cursors, listSpec(CursorField)); + + return (cursors || []).filter(cursor => cursor.data.metadata.id !== id); } private crosshairs?: HTMLCanvasElement; drawCrosshairs = (backgroundColor: string) => { if (this.crosshairs) { - let c = this.crosshairs; - let ctx = c.getContext('2d'); + let ctx = this.crosshairs.getContext('2d'); if (ctx) { ctx.fillStyle = backgroundColor; ctx.fillRect(0, 0, 20, 20); @@ -49,29 +58,26 @@ export class CollectionFreeFormRemoteCursors extends React.Component<CollectionV } } } - @computed + get sharedCursors() { - return this.getCursors().map(entry => { - if (entry.Data.length > 0) { - let id = entry.Data[0][0]; - let email = entry.Data[0][1]; - let point = entry.Data[1]; - this.drawCrosshairs("#" + v5(id, v5.URL).substring(0, 6).toUpperCase() + "22"); - return ( - <div key={id} className="collectionFreeFormRemoteCursors-cont" - style={{ transform: `translate(${point[0] - 10}px, ${point[1] - 10}px)` }} - > - <canvas className="collectionFreeFormRemoteCursors-canvas" - ref={(el) => { if (el) this.crosshairs = el; }} - width={20} - height={20} - /> - <p className="collectionFreeFormRemoteCursors-symbol"> - {email[0].toUpperCase()} - </p> - </div> - ); - } + return this.getCursors().map(c => { + let m = c.data.metadata; + let l = c.data.position; + this.drawCrosshairs("#" + v5(m.id, v5.URL).substring(0, 6).toUpperCase() + "22"); + return ( + <div key={m.id} className="collectionFreeFormRemoteCursors-cont" + style={{ transform: `translate(${l.x - 10}px, ${l.y - 10}px)` }} + > + <canvas className="collectionFreeFormRemoteCursors-canvas" + ref={(el) => { if (el) this.crosshairs = el; }} + width={20} + height={20} + /> + <p className="collectionFreeFormRemoteCursors-symbol"> + {m.identifier[0].toUpperCase()} + </p> + </div> + ); }); } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 797f94d5f..7ab09987f 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -70,7 +70,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { } public getActiveDocuments = () => { const curPage = FieldValue(this.Document.curPage, -1); - return FieldValue(this.children, [] as Doc[]).filter(doc => { + return this.children.filter(doc => { var page = NumCast(doc.page, -1); return page === curPage || page === -1; }); @@ -309,7 +309,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { {this.childViews} </InkingCanvas> </CollectionFreeFormLinksView> - {/* <CollectionFreeFormRemoteCursors {...this.props} key="remoteCursors" /> */} + <CollectionFreeFormRemoteCursors {...this.props} key="remoteCursors" /> </CollectionFreeFormViewPannableContents> </MarqueeView> <CollectionFreeFormOverlayView {...this.getDocumentViewProps(this.props.Document)} {...this.props} /> diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 0345d5efd..37428e88b 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -169,7 +169,7 @@ export class MarqueeView extends React.Component<MarqueeViewProps> if (this._commandExecuted) { return; } - if (e.key === "Backspace" || e.key === "Delete" || e.key == "d") { + if (e.key === "Backspace" || e.key === "Delete" || e.key === "d") { this._commandExecuted = true; this.marqueeSelect().map(d => this.props.removeDocument(d)); let ink = Cast(this.props.container.props.Document.ink, InkField); @@ -235,7 +235,7 @@ export class MarqueeView extends React.Component<MarqueeViewProps> let maxy = NumCast(maximizedDoc.y, undefined); let maxw = NumCast(maximizedDoc.width, undefined); let maxh = NumCast(maximizedDoc.height, undefined); - maximizedDoc.isIconAnimating = new List<number>([scrpt[0], scrpt[1], maxx, maxy, maxw, maxh, Date.now(), 0]) + maximizedDoc.isIconAnimating = new List<number>([scrpt[0], scrpt[1], maxx, maxy, maxw, maxh, Date.now(), 0]); }); this.props.addLiveTextDocument(summary); } diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 470c0c2f8..fb182847e 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -202,8 +202,8 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF } } - onPointerEnter = (e: React.PointerEvent): void => { this.props.Document.libraryBrush = true; } - onPointerLeave = (e: React.PointerEvent): void => { this.props.Document.libraryBrush = false; } + onPointerEnter = (e: React.PointerEvent): void => { this.props.Document.libraryBrush = true; }; + onPointerLeave = (e: React.PointerEvent): void => { this.props.Document.libraryBrush = false; }; borderRounding = () => { let br = NumCast(this.props.Document.borderRounding); diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 4b3172e82..a688a6272 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -92,7 +92,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe let titlestr = str.substr(0, Math.min(40, str.length)); let target = this.props.Document.proto ? this.props.Document.proto : this.props.Document; target.title = "-" + titlestr + (str.length > 40 ? "..." : ""); - }; + } } } @@ -182,8 +182,9 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe onPointerDown = (e: React.PointerEvent): void => { if (e.button === 0 && this.props.isSelected() && !e.altKey && !e.ctrlKey && !e.metaKey) { e.stopPropagation(); - if (this._toolTipTextMenu && this._toolTipTextMenu.tooltip) + if (this._toolTipTextMenu && this._toolTipTextMenu.tooltip) { this._toolTipTextMenu.tooltip.style.opacity = "0"; + } } if (e.button === 2 || (e.button === 0 && e.ctrlKey)) { this._gotDown = true; @@ -191,8 +192,9 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe } } onPointerUp = (e: React.PointerEvent): void => { - if (this._toolTipTextMenu && this._toolTipTextMenu.tooltip) + if (this._toolTipTextMenu && this._toolTipTextMenu.tooltip) { this._toolTipTextMenu.tooltip.style.opacity = "1"; + } if (e.buttons === 1 && this.props.isSelected() && !e.altKey) { e.stopPropagation(); } diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index eb45ea273..caa66cbeb 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -215,8 +215,9 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen if (e.altKey) { this._alt = true; } else { - if (e.metaKey) + if (e.metaKey) { e.stopPropagation(); + } } document.removeEventListener("pointerup", this.onPointerUp); document.addEventListener("pointerup", this.onPointerUp); @@ -286,7 +287,7 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen renderHeight = 2400; @computed get pdfPage() { - return <Page height={this.renderHeight} pageNumber={this.curPage} onLoadSuccess={this.onLoaded} /> + return <Page height={this.renderHeight} pageNumber={this.curPage} onLoadSuccess={this.onLoaded} />; } @computed get pdfContent() { diff --git a/src/new_fields/CursorField.ts b/src/new_fields/CursorField.ts new file mode 100644 index 000000000..7fd326a5f --- /dev/null +++ b/src/new_fields/CursorField.ts @@ -0,0 +1,55 @@ +import { ObjectField, Copy, OnUpdate } from "./ObjectField"; +import { observable } from "mobx"; +import { Deserializable } from "../client/util/SerializationHelper"; +import { serializable, createSimpleSchema, object } from "serializr"; + +export type CursorPosition = { + x: number, + y: number +} + +export type CursorMetadata = { + id: string, + identifier: string +} + +export type CursorData = { + metadata: CursorMetadata, + position: CursorPosition +} + +const PositionSchema = createSimpleSchema({ + x: true, + y: true +}); + +const MetadataSchema = createSimpleSchema({ + id: true, + identifier: true +}); + +const CursorSchema = createSimpleSchema({ + metadata: object(MetadataSchema), + position: object(PositionSchema) +}); + +@Deserializable("cursor") +export default class CursorField extends ObjectField { + + @serializable(object(CursorSchema)) + readonly data: CursorData; + + constructor(data: CursorData) { + super(); + this.data = data; + } + + setPosition(position: CursorPosition) { + this.data.position = position; + this[OnUpdate](); + } + + [Copy]() { + return new CursorField(this.data); + } +}
\ No newline at end of file diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index afcf71fc9..f844dad6e 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -25,7 +25,7 @@ export type FieldResult<T extends Field = Field> = Opt<T> | FieldWaiting<Extract export const Update = Symbol("Update"); export const Self = Symbol("Self"); -const SelfProxy = Symbol("SelfProxy"); +export const SelfProxy = Symbol("SelfProxy"); export const WidthSym = Symbol("Width"); export const HeightSym = Symbol("Height"); diff --git a/src/new_fields/InkField.ts b/src/new_fields/InkField.ts index 86a8bd18a..2d75f8a19 100644 --- a/src/new_fields/InkField.ts +++ b/src/new_fields/InkField.ts @@ -1,8 +1,6 @@ import { Deserializable } from "../client/util/SerializationHelper"; import { serializable, custom, createSimpleSchema, list, object, map } from "serializr"; import { ObjectField, Copy } from "./ObjectField"; -import { number } from "prop-types"; -import { any } from "bluebird"; import { deepCopy } from "../Utils"; export enum InkTool { @@ -11,6 +9,7 @@ export enum InkTool { Highlighter, Eraser } + export interface StrokeData { pathData: Array<{ x: number, y: number }>; color: string; @@ -39,6 +38,6 @@ export class InkField extends ObjectField { } [Copy]() { - return new InkField(deepCopy(this.inkData)) + return new InkField(deepCopy(this.inkData)); } } diff --git a/src/new_fields/List.ts b/src/new_fields/List.ts index 5aba64406..88a65eba4 100644 --- a/src/new_fields/List.ts +++ b/src/new_fields/List.ts @@ -1,9 +1,9 @@ import { Deserializable, autoObject } from "../client/util/SerializationHelper"; -import { Field, Update, Self, FieldResult } from "./Doc"; -import { setter, getter, deleteProperty } from "./util"; +import { Field, Update, Self, FieldResult, SelfProxy } from "./Doc"; +import { setter, getter, deleteProperty, updateFunction } from "./util"; import { serializable, alias, list } from "serializr"; import { observable, action } from "mobx"; -import { ObjectField, OnUpdate, Copy } from "./ObjectField"; +import { ObjectField, OnUpdate, Copy, Parent } from "./ObjectField"; import { RefField } from "./RefField"; import { ProxyField } from "./Proxy"; @@ -27,7 +27,17 @@ const listHandlers: any = { }, push: action(function (this: any, ...items: any[]) { items = items.map(toObjectField); - const res = this[Self].__fields.push(...items); + const list = this[Self]; + const length = list.__fields.length; + for (let i = 0; i < items.length; i++) { + const item = items[i]; + //TODO Error checking to make sure parent doesn't already exist + if (item instanceof ObjectField) { + item[Parent] = list; + item[OnUpdate] = updateFunction(list, i + length, item, this); + } + } + const res = list.__fields.push(...items); this[Update](); return res; }), @@ -48,12 +58,33 @@ const listHandlers: any = { }, splice: action(function (this: any, start: number, deleteCount: number, ...items: any[]) { items = items.map(toObjectField); - const res = this[Self].__fields.splice(start, deleteCount, ...items); + const list = this[Self]; + for (let i = 0; i < items.length; i++) { + const item = items[i]; + //TODO Error checking to make sure parent doesn't already exist + //TODO Need to change indices of other fields in array + if (item instanceof ObjectField) { + item[Parent] = list; + item[OnUpdate] = updateFunction(list, i + start, item, this); + } + } + const res = list.__fields.splice(start, deleteCount, ...items); this[Update](); return res.map(toRealField); }), unshift(...items: any[]) { items = items.map(toObjectField); + const list = this[Self]; + const length = list.__fields.length; + for (let i = 0; i < items.length; i++) { + const item = items[i]; + //TODO Error checking to make sure parent doesn't already exist + //TODO Need to change indices of other fields in array + if (item instanceof ObjectField) { + item[Parent] = list; + item[OnUpdate] = updateFunction(list, i, item, this); + } + } const res = this[Self].__fields.unshift(...items); this[Update](); return res; @@ -202,6 +233,7 @@ class ListImpl<T extends Field> extends ObjectField { deleteProperty: deleteProperty, defineProperty: () => { throw new Error("Currently properties can't be defined on documents using Object.defineProperty"); }, }); + this[SelfProxy] = list; (list as any).push(...fields); return list; } @@ -215,6 +247,12 @@ class ListImpl<T extends Field> extends ObjectField { private set __fields(value) { this.___fields = value; + for (const key in value) { + const field = value[key]; + if (!(field instanceof ObjectField)) continue; + (field as ObjectField)[Parent] = this[Self]; + (field as ObjectField)[OnUpdate] = updateFunction(this[Self], key, field, this[SelfProxy]); + } } [Copy]() { @@ -235,6 +273,7 @@ class ListImpl<T extends Field> extends ObjectField { } private [Self] = this; + private [SelfProxy]: any; } export type List<T extends Field> = ListImpl<T> & (T | (T extends RefField ? Promise<T> : never))[]; export const List: { new <T extends Field>(fields?: T[]): List<T> } = ListImpl as any;
\ No newline at end of file diff --git a/src/new_fields/ObjectField.ts b/src/new_fields/ObjectField.ts index 0f3777af6..f276bfa67 100644 --- a/src/new_fields/ObjectField.ts +++ b/src/new_fields/ObjectField.ts @@ -1,12 +1,13 @@ import { Doc } from "./Doc"; +import { RefField } from "./RefField"; export const OnUpdate = Symbol("OnUpdate"); export const Parent = Symbol("Parent"); export const Copy = Symbol("Copy"); export abstract class ObjectField { - protected [OnUpdate]?: (diff?: any) => void; - private [Parent]?: Doc; + protected [OnUpdate](diff?: any) { }; + private [Parent]?: RefField | ObjectField; abstract [Copy](): ObjectField; } |