summaryrefslogtreecommitdiff
path: root/web/src/doc/index.ts
blob: a58faa6fcd0ded6d8fde7abebbd83da96daf4abc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
export abstract class DocOp {
  abstract key: string;
}

export class CreateGridOp extends DocOp {
  gridId: string = crypto.randomUUID();
  rows = 4;
  key = this.gridId;
  baseCellsPerRow = 16;
}

export default class Doc {
  readonly ops: DocOp[];

  readonly opsByKey: Map<string, readonly DocOp[]>;
  readonly opsByType: Map<Function, readonly DocOp[]>;

  constructor(ops: DocOp[]) {
    this.ops = ops;

    const opsByKey = new Map();
    const opsByType = new Map();

    for (const op of ops) {
      const maybeKeyOps = opsByKey.get(op.key);

      if (maybeKeyOps) maybeKeyOps.push(op);
      else opsByKey.set(op.key, [op]);

      const maybeTypeOps = opsByType.get(op.constructor);

      if (maybeTypeOps) maybeTypeOps.push(op);
      else opsByType.set(op.constructor, [op]);
    }

    this.opsByKey = opsByKey;
    this.opsByType = opsByType;
  }

  static default(): Doc {
    return new Doc([new CreateGridOp()]);
  }

  get grids(): Grid[] {
    const ops = this.opsByType.get(CreateGridOp) ?? [];
    return ops.map((op) => new Grid(this, op as CreateGridOp));
  }
}

export class Grid {
  readonly doc: Doc;
  readonly id: string;
  readonly rows: readonly Row[];

  constructor(doc: Doc, createOp: CreateGridOp) {
    this.doc = doc;
    this.id = createOp.gridId;

    const rows: Row[] = [];

    for (let rowIndex = 0; rowIndex < createOp.rows; rowIndex++) {
      rows.push(new Row(doc, this.id, rowIndex));
    }

    this.rows = rows;
  }
}

export class Row {
  readonly doc: Doc;
  readonly gridId: string;
  readonly index: number;
  readonly cells: readonly Cell[];

  constructor(doc: Doc, gridId: string, index: number) {
    this.doc = doc;
    this.gridId = gridId;
    this.index = index;

    const createGridOp = doc.opsByType
      .get(CreateGridOp)
      ?.find((op) => op.key === gridId)! as CreateGridOp;

    const cells: Cell[] = [];

    for (
      let cellIndex = 0;
      cellIndex < createGridOp.baseCellsPerRow;
      cellIndex++
    ) {
      cells.push(new Cell(doc, gridId, index, cellIndex));
    }

    this.cells = cells;
  }
}

export class Cell {
  readonly doc: Doc;
  readonly gridId: string;
  readonly rowIndex: number;
  readonly index: number;

  constructor(doc: Doc, gridId: string, rowIndex: number, index: number) {
    this.doc = doc;
    this.gridId = gridId;
    this.rowIndex = rowIndex;
    this.index = index;
  }
}