diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/client/views/collections/CollectionSubView.tsx | 21 | ||||
-rw-r--r-- | src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx | 66 | ||||
-rw-r--r-- | src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx | 4 | ||||
-rw-r--r-- | src/new_fields/CursorField.ts | 55 | ||||
-rw-r--r-- | src/new_fields/InkField.ts | 3 | ||||
-rw-r--r-- | src/new_fields/List.ts | 39 | ||||
-rw-r--r-- | src/new_fields/TupleField.ts | 63 |
7 files changed, 140 insertions, 111 deletions
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 1e8723fc6..232679a59 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -10,14 +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 { TupleField } from "../../../new_fields/TupleField"; +import CursorField, { CursorPosition, CursorMetadata } from "../../../new_fields/CursorField"; export interface CollectionViewProps extends FieldViewProps { addDocument: (document: Doc, allowDuplicates?: boolean) => boolean; @@ -31,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; @@ -56,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(TupleField)); + let cursors = Cast(proto.cursors, listSpec(CursorField)); if (!cursors) { - proto!.cursors = cursors = new List<TupleField<[]>>(); + 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/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx index 036745eca..c22f430ac 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx @@ -1,26 +1,38 @@ 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)); + if (!cursors) { + doc.cursors = cursors = new List<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 +61,27 @@ 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 17c25c9db..59f7fa442 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; }); @@ -314,7 +314,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { {this.childViews} </InkingCanvas> </CollectionFreeFormLinksView> - {/* <CollectionFreeFormRemoteCursors {...this.props} key="remoteCursors" /> */} + <CollectionFreeFormRemoteCursors {...this.props} key="remoteCursors" /> </CollectionFreeFormViewPannableContents> <CollectionFreeFormOverlayView {...this.getDocumentViewProps(this.props.Document)} {...this.props} /> </MarqueeView> 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/InkField.ts b/src/new_fields/InkField.ts index a3157857f..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; diff --git a/src/new_fields/List.ts b/src/new_fields/List.ts index 96018dafa..3e5fee646 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 { 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; diff --git a/src/new_fields/TupleField.ts b/src/new_fields/TupleField.ts deleted file mode 100644 index 1ff57fefc..000000000 --- a/src/new_fields/TupleField.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { ObjectField, Copy } from "./ObjectField"; -import { IObservableArray, IArrayChange, IArraySplice, observe, Lambda, observable } from "mobx"; -import { UndoManager } from "../client/util/UndoManager"; -import { Field } from "./Doc"; -import { Deserializable } from "../client/util/SerializationHelper"; -import { serializable, createSimpleSchema, list, object } from "serializr"; -import { array } from "prop-types"; - -const tupleSchema = createSimpleSchema({ - -}); - -@Deserializable("tuple") -export class TupleField<T, U> extends ObjectField { - - - @serializable(list(object(tupleSchema))) - private Data: [T, U]; - - public get data() { - return this.Data; - } - - constructor(data: [T, U]) { - super(); - this.Data = data; - this.observeTuple(); - } - - private observeDisposer: Lambda | undefined; - private observeTuple(): void { - this.observeDisposer = observe(this.Data as (T | U)[] as IObservableArray<T | U>, (change: IArrayChange<T | U> | IArraySplice<T | U>) => { - if (change.type === "update") { - UndoManager.AddEvent({ - undo: () => this.Data[change.index] = change.oldValue, - redo: () => this.Data[change.index] = change.newValue - }); - } else { - throw new Error("Why are you messing with the length of a tuple, huh?"); - } - }); - } - - protected setData(value: [T, U]) { - if (this.observeDisposer) { - this.observeDisposer(); - } - this.Data = observable(value) as (T | U)[] as [T, U]; - this.observeTuple(); - } - - UpdateFromServer(values: [T, U]) { - this.setData(values); - } - - ToScriptString(): string { - return `new TupleField([${this.Data[0], this.Data[1]}])`; - } - - [Copy]() { - return new TupleField<T, U>(this.Data); - } -}
\ No newline at end of file |