diff --git a/src/common/dialog/DocumentPickerDialog.svelte b/src/common/dialog/DocumentPickerDialog.svelte
index c18d95707..e4a57a725 100644
--- a/src/common/dialog/DocumentPickerDialog.svelte
+++ b/src/common/dialog/DocumentPickerDialog.svelte
@@ -1,5 +1,5 @@
{#if $modification.modifyHasSelection}
@@ -27,28 +30,28 @@
{/if}
-
{#if $modification.hasInsert}
- modification.pasteAtInsert()}
+ $modification.pasteAtInsert()}
>{$_("modifyPane.insert")}
{:else}
- modification.pasteAtEnd()}
+ $modification.pasteAtEnd()}
>{$_("modifyPane.insertAtEnd")}
{/if}
- modification.clearCopyBuffer()}>
+ $modification.clearCopyBuffer()}>
{$_("dialog.cancel")}
@@ -134,7 +137,7 @@
{$_("modifyPane.insertOtherDoc")}
- modification.clearInsertion()}>
+ $modification.clearInsertion()}>
{$_("dialog.cancel")}
@@ -151,7 +154,7 @@
{
- modify(modification, cancelActions);
+ modify($modification, cancelActions);
}}
>
{$_("modifyPane.applyModifications")}
@@ -160,12 +163,12 @@
modification.undo()}>{$_("modifyPane.undo")} $modification.undo()}>{$_("modifyPane.undo")}
modification.redo()}>{$_("modifyPane.redo")} $modification.redo()}>{$_("modifyPane.redo")}
{/if}
diff --git a/src/viewer/layout.js b/src/viewer/layout.js
index c52eed7e5..b846fab9a 100644
--- a/src/viewer/layout.js
+++ b/src/viewer/layout.js
@@ -21,7 +21,7 @@ import {
import { Note } from "@/structure/note.js";
import { DEFAULT_EXPAND } from "../api/common.js";
import { inIframe } from "@/util/iframe.js";
-import { modification } from "./modification/modification.js";
+import { modification } from "./modification/modification.ts";
import {
MOBILE_BREAKPOINT,
diff --git a/src/viewer/modification/modification.test.js b/src/viewer/modification/modification.test.ts
similarity index 93%
rename from src/viewer/modification/modification.test.js
rename to src/viewer/modification/modification.test.ts
index 7ac6230ad..f41983da0 100644
--- a/src/viewer/modification/modification.test.js
+++ b/src/viewer/modification/modification.test.ts
@@ -1,7 +1,10 @@
-import { modification } from "./modification.js";
-import { ModificationSpec } from "./modifySpec.js";
+import { Modification } from "./modification";
+import { ModificationSpec } from "./modifySpec";
+
+let modification;
beforeEach(() => {
+ modification = new Modification();
modification.clear();
modification.initSpec(ModificationSpec.getDocument(3));
});
diff --git a/src/viewer/modification/modification.js b/src/viewer/modification/modification.ts
similarity index 54%
rename from src/viewer/modification/modification.js
rename to src/viewer/modification/modification.ts
index f44a04a98..902685261 100644
--- a/src/viewer/modification/modification.js
+++ b/src/viewer/modification/modification.ts
@@ -1,102 +1,124 @@
-import { Svue } from "svue";
+import { Writable, writable } from "svelte/store";
import {
runify,
Empty,
Individual,
ModificationSpec,
CLOCKWISE,
-} from "./modifySpec.js";
+} from "./modifySpec";
+
+// TODO replace with typed and de-Svue'd `structure/Document`
+interface Document {
+ pageCount: number;
+ id: string;
+}
+
+export class Modification {
+ copyBuffer: ModificationSpec | null;
+ modifySelectedMap: Record;
+ rewind: boolean;
+ insert: null;
+ history: ModificationSpec[];
+ historyPosition: number;
+ insertDocument: Document | null;
+ documentCache: Record;
-class Modification extends Svue {
constructor() {
- super({
- data() {
- return {
- copyBuffer: null,
- modifySelectedMap: {},
- rewind: false,
- insert: null,
- history: [],
- historyPosition: 0,
- insertDocument: null,
- documentCache: {},
- };
- },
- computed: {
- historyLength(history) {
- return history.length;
- },
- modifySpec(history, historyLength, historyPosition) {
- if (historyLength == 0) return null;
- return history[historyPosition];
- },
- pageCount(modifySpec) {
- if (modifySpec == null) return 0;
- return modifySpec.length();
- },
- modifySelected(modifySelectedMap) {
- const results = [];
- for (let key in modifySelectedMap) {
- if (
- modifySelectedMap.hasOwnProperty(key) &&
- modifySelectedMap[key] == true
- ) {
- results.push(key);
- }
- }
- return results;
- },
- modifyNumSelected(modifySelected) {
- return modifySelected.length;
- },
- modifyHasSelection(modifyNumSelected) {
- const hasSelection = modifyNumSelected > 0;
- if (hasSelection) {
- this.clearInsertion();
- }
- return hasSelection;
- },
- modifySelectedPageSpec(modifySelected) {
- return runify(modifySelected);
- },
- modifySelectedSpec(modifySpec, modifySelectedPageSpec) {
- if (modifySpec == null) return null;
- const selectedSpec = new ModificationSpec(
- modifySelectedPageSpec.specs.reduce((prev, spec) => {
- if (spec instanceof Empty) return prev;
- if (spec instanceof Individual)
- return prev.concat(modifySpec.slice(spec.pg, 1).specs);
- return prev.concat(
- modifySpec.slice(spec.start, spec.length()).specs,
- );
- }, []),
- ).compress();
- return selectedSpec;
- },
- hasInsert(insert) {
- return insert != null;
- },
- hasCopyBuffer(copyBuffer) {
- return copyBuffer != null;
- },
- copyBufferLength(copyBuffer) {
- if (copyBuffer == null) return 0;
- return copyBuffer.length();
- },
- canUndo(historyPosition) {
- return historyPosition > 0;
- },
- canRedo(historyLength, historyPosition) {
- return historyPosition + 1 < historyLength;
- },
- hasHistory(historyLength) {
- return historyLength > 1;
- },
- uncommittedChanges(historyPosition) {
- return historyPosition > 0;
- },
- },
- });
+ this.copyBuffer = null;
+ this.modifySelectedMap = {};
+ this.rewind = false;
+ this.insert = null;
+ this.history = [];
+ this.historyPosition = 0;
+ this.insertDocument = null;
+ this.documentCache = null;
+ }
+
+ get historyLength() {
+ return this.history.length;
+ }
+
+ get modifySpec() {
+ if (this.historyLength === 0) return null;
+ return this.history[this.historyPosition];
+ }
+
+ get pageCount() {
+ if (this.modifySpec === null) return 0;
+ return this.modifySpec.length();
+ }
+
+ get modifySelected() {
+ const results = [];
+ for (let key in this.modifySelectedMap) {
+ if (
+ this.modifySelectedMap.hasOwnProperty(key) &&
+ this.modifySelectedMap[key] == true
+ ) {
+ results.push(key);
+ }
+ }
+ return results;
+ }
+
+ get modifyNumSelected() {
+ return this.modifySelected.length;
+ }
+
+ get modifyHasSelection() {
+ const hasSelection = this.modifyNumSelected > 0;
+ if (hasSelection) {
+ this.clearInsertion();
+ }
+ return hasSelection;
+ }
+
+ get modifySelectedPageSpec() {
+ return runify(this.modifySelected);
+ }
+
+ get modifySelectedSpec() {
+ if (this.modifySpec == null) return null;
+ const selectedSpec = new ModificationSpec(
+ this.modifySelectedPageSpec.specs.reduce((prev, spec) => {
+ if (spec instanceof Empty) return prev;
+ if (spec instanceof Individual)
+ return prev.concat(this.modifySpec.slice(spec.pg, 1).specs);
+ return prev.concat(
+ this.modifySpec.slice(spec.start, spec.length()).specs,
+ );
+ }, []),
+ ).compress();
+ return selectedSpec;
+ }
+
+ get hasInsert() {
+ return this.insert != null;
+ }
+
+ get hasCopyBuffer() {
+ return this.copyBuffer != null;
+ }
+
+ get copyBufferLength() {
+ if (this.copyBuffer === null) return 0;
+ return this.copyBuffer.length();
+ }
+
+ get canUndo() {
+ return this.historyPosition > 0;
+ }
+
+ get canRedo() {
+ return this.historyPosition + 1 < this.historyLength;
+ }
+
+ get hasHistory() {
+ return this.historyLength > 1;
+ }
+
+ get uncommittedChanges() {
+ return this.historyPosition > 0;
}
modifyUnselect() {
@@ -250,4 +272,6 @@ class Modification extends Svue {
}
}
-export const modification = new Modification();
+export const modification: Writable = writable(
+ new Modification(),
+);
diff --git a/src/viewer/modification/modifySpec.test.js b/src/viewer/modification/modifySpec.test.ts
similarity index 100%
rename from src/viewer/modification/modifySpec.test.js
rename to src/viewer/modification/modifySpec.test.ts
diff --git a/src/viewer/modification/modifySpec.js b/src/viewer/modification/modifySpec.ts
similarity index 94%
rename from src/viewer/modification/modifySpec.js
rename to src/viewer/modification/modifySpec.ts
index 863f949d1..73652a22a 100644
--- a/src/viewer/modification/modifySpec.js
+++ b/src/viewer/modification/modifySpec.ts
@@ -1,4 +1,4 @@
-import { arrayEq } from "@/util/array.js";
+import { arrayEq } from "../../util/array.js";
export class Empty {
constructor() {}
@@ -11,7 +11,7 @@ export class Empty {
return "";
}
- index(_) {
+ index(_: unknown) {
return null;
}
@@ -19,13 +19,16 @@ export class Empty {
return 0;
}
- slice(_a, _b) {
+ slice(_a: unknown, _b: unknown) {
return new Empty();
}
}
export class Range {
- constructor(startInclusive, endInclusive) {
+ start: number;
+ end: number;
+
+ constructor(startInclusive: number, endInclusive: number) {
this.start = startInclusive;
this.end = endInclusive;
}
@@ -42,7 +45,7 @@ export class Range {
return `${this.start}-${this.end}`;
}
- index(i) {
+ index(i: number) {
return this.start + i;
}
@@ -50,7 +53,7 @@ export class Range {
return this.end - this.start + 1;
}
- slice(i, l) {
+ slice(i: number, l: number) {
const start = this.start + i;
const end = this.start + i + l - 1;
if (start == end) return new Individual(start);
@@ -60,7 +63,9 @@ export class Range {
}
export class Individual {
- constructor(pg) {
+ pg: number;
+
+ constructor(pg: number) {
this.pg = pg;
}
@@ -80,7 +85,7 @@ export class Individual {
return 1;
}
- slice(i, l) {
+ slice(i: number, l: number) {
if (i != 0 || l < 1) {
return new Empty();
}
@@ -89,6 +94,7 @@ export class Individual {
}
export class PageSpec {
+ specs: (Individual | Range)[];
constructor(specs) {
this.specs = specs;
}
@@ -289,9 +295,13 @@ const ROTATION_MATRIX = {
[HALFWAY]: null,
},
};
+
export const ROTATE = "rotate";
+
export class Rotation {
- constructor(angle) {
+ type: typeof ROTATE;
+ angle: typeof CLOCKWISE | typeof COUNTER_CLOCKWISE | typeof HALFWAY;
+ constructor(angle: "cc" | "ccw" | "hw") {
this.type = ROTATE;
this.angle = angle;
}
@@ -303,12 +313,17 @@ export class Rotation {
};
}
- eq(other) {
+ eq(other: Rotation) {
return other.type == ROTATE && other.angle == this.angle;
}
}
+type Modification = Rotation;
+
export class ModificationDescriptor {
+ pageSpec: PageSpec;
+ modifications: Modification[];
+ id: string | null;
constructor(pageSpec, modifications = [], id = null) {
this.pageSpec = pageSpec;
this.modifications = modifications;
@@ -353,7 +368,11 @@ export class ModificationDescriptor {
}
json() {
- const json = {};
+ const json: {
+ id?: string;
+ page?: string;
+ modifications?: Modification[];
+ } = {};
json.page = this.pageSpec.spec();
if (this.id != null) json.id = this.id;
if (this.modifications.length > 0) json.modifications = this.modifications;
@@ -438,6 +457,8 @@ export class ModificationDescriptor {
}
export class ModificationSpec {
+ specs: ModificationDescriptor[];
+ pageSpec: PageSpec;
constructor(specs) {
this.specs = specs;