diff --git a/src/cti_authoring_tool/CHANGELOG.md b/src/cti_authoring_tool/CHANGELOG.md
index 3023a5d..9d5db58 100644
--- a/src/cti_authoring_tool/CHANGELOG.md
+++ b/src/cti_authoring_tool/CHANGELOG.md
@@ -2,6 +2,17 @@
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
+### [0.1.3](///compare/v0.1.2...v0.1.3) (2023-06-06)
+
+
+### Features
+
+* add file save/open functionality 3a4bdc8
+* add redesigned Page library 9dc899b
+* add redesigned Page Management library 7bc0821
+* restructure and expand Web Utilities library b8a66fa
+* restructure core application library 9c6f877
+
### [0.1.2](///compare/v0.1.1...v0.1.2) (2023-04-10)
diff --git a/src/cti_authoring_tool/package-lock.json b/src/cti_authoring_tool/package-lock.json
index 0464698..8ba21dd 100644
--- a/src/cti_authoring_tool/package-lock.json
+++ b/src/cti_authoring_tool/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "cti-authoring-tool",
- "version": "0.1.2",
+ "version": "0.1.3",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "cti-authoring-tool",
- "version": "0.1.2",
+ "version": "0.1.3",
"dependencies": {
"vue": "^3.2.41",
"vuex": "^4.0.0-0"
diff --git a/src/cti_authoring_tool/package.json b/src/cti_authoring_tool/package.json
index c023b58..0c9e73b 100644
--- a/src/cti_authoring_tool/package.json
+++ b/src/cti_authoring_tool/package.json
@@ -1,6 +1,6 @@
{
"name": "cti-authoring-tool",
- "version": "0.1.2",
+ "version": "0.1.3",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
diff --git a/src/cti_authoring_tool/src/App.vue b/src/cti_authoring_tool/src/App.vue
index 14aca98..e54c3c9 100644
--- a/src/cti_authoring_tool/src/App.vue
+++ b/src/cti_authoring_tool/src/App.vue
@@ -1,10 +1,10 @@
-
+
import * as Store from "@/store/StoreTypes";
-import * as App from "@/assets/scripts/Commands/AppCommands";
+import * as AppCommands from "@/assets/scripts/Application/Commands";
import Configuration from "@/assets/configuration/app.config"
// Dependencies
-import { Command } from "./assets/scripts/Commands/Command";
-import { PageEditor } from "./assets/scripts/Page/PageEditor";
+import { Command } from "./assets/scripts/Application/Command";
+import { PageEditor } from "./assets/scripts/PageEditor/PageEditor";
import { defineComponent } from 'vue';
import { mapMutations, mapState } from 'vuex';
// Components
@@ -69,11 +69,11 @@ export default defineComponent({
...mapMutations("ApplicationStore", ["execute"]),
/**
- * Page command behavior.
+ * Page execute behavior.
* @param emitter
* The page's command.
*/
- async onCommand(cmd: Command) {
+ async onExecute(cmd: Command) {
try {
if(cmd instanceof Promise) {
this.execute(await cmd);
@@ -91,7 +91,7 @@ export default defineComponent({
* The editor's id.
*/
onEditorSwitch(id: string) {
- this.execute(new App.SwitchActiveFile(this.ctx, id));
+ this.execute(AppCommands.switchActivePage(this.ctx, id));
},
/**
@@ -100,7 +100,7 @@ export default defineComponent({
* The editor's id.
*/
onEditorClose(id: string) {
- this.execute(new App.UnloadFile(this.ctx, id));
+ this.execute(AppCommands.unloadPage(this.ctx, id));
}
@@ -114,7 +114,7 @@ export default defineComponent({
settings = require("../public/settings.json");
}
// Load settings
- this.execute(new App.LoadSettings(this.ctx, settings));
+ this.execute(AppCommands.loadSettings(this.ctx, settings));
},
components: {
ScrollBox, AppTitleBar, AppHotkeyBox,
diff --git a/src/cti_authoring_tool/src/assets/configuration/app.config.ts b/src/cti_authoring_tool/src/assets/configuration/app.config.ts
index e4e099c..bbfb6ed 100644
--- a/src/cti_authoring_tool/src/assets/configuration/app.config.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/app.config.ts
@@ -1,8 +1,8 @@
-import { AppConfiguration, PropertyType } from "../scripts/AppConfiguration";
-import { ThreatActorProfile } from "./templates/ThreatActorProfile";
import { Campaign } from "./templates/Campaign";
-import { IntrusionAnalysis } from "./templates/IntrusionAnalysis";
import { Executive } from "./templates/Executive";
+import { IntrusionAnalysis } from "./templates/IntrusionAnalysis";
+import { ThreatActorProfile } from "./templates/ThreatActorProfile";
+import { AppConfiguration } from "@/assets/scripts/Application/AppConfiguration";
const config: AppConfiguration = {
is_web_hosted: false,
diff --git a/src/cti_authoring_tool/src/assets/configuration/plugins/ImportCSVPlugin.ts b/src/cti_authoring_tool/src/assets/configuration/plugins/ImportCSVPlugin.ts
new file mode 100644
index 0000000..d8943f5
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/configuration/plugins/ImportCSVPlugin.ts
@@ -0,0 +1,52 @@
+import { Browser } from "@/assets/scripts/Utilities/Browser";
+import { TabularProperty } from "@/assets/scripts/Page";
+
+export class ImportCSVPlugin {
+
+ /**
+ * Creates a new {@link ImportCSVPlugin}.
+ * @param property
+ * The tabular property.
+ */
+ constructor(property: TabularProperty) {
+ // Register "Import from CSV" action
+ property.registerAction("import-csv", "Import from CSV", () => {
+ Browser.openTextFileDialog().then(file => {
+ let { contents } = file;
+ // Validate contents
+ if(contents === null || contents === undefined) {
+ console.error(`Error: could not contents of file: '${ file.filename }'.`);
+ }
+ // Parse contents
+ let objs = this.parseCsv(file.contents as string);
+ // Add contents
+ for(let obj of objs) {
+ property.insertRow(property.createRow(obj));
+ }
+ });
+ });
+ }
+
+ /**
+ * Parses a simple CSV file.
+ * @param contents
+ * The CSV file's contents.
+ * @returns
+ * The parsed CSV file.
+ */
+ private parseCsv(contents: string): any[] {
+ let objs = [];
+ let lines = contents.split(/\r?\n/g);
+ let head = lines[0].split(/,/g);
+ for(let i = 1; i < lines.length; i++) {
+ let obj = []
+ let cells = lines[i].split(/\,/g);
+ for(let j = 0; j < head.length; j++) {
+ obj.push([head[j], cells[j]]);
+ }
+ objs.push(Object.fromEntries(obj));
+ }
+ return objs;
+ }
+
+}
diff --git a/src/cti_authoring_tool/src/assets/configuration/plugins/ReportNumberPlugin.ts b/src/cti_authoring_tool/src/assets/configuration/plugins/ReportNumberPlugin.ts
index e509be5..d4f01f8 100644
--- a/src/cti_authoring_tool/src/assets/configuration/plugins/ReportNumberPlugin.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/plugins/ReportNumberPlugin.ts
@@ -1,4 +1,4 @@
-import { IStringProperty } from "@/assets/scripts/Page/Property/StringProperty/IStringProperty";
+import { StringProperty } from "@/assets/scripts/Page";
export class ReportNumberPlugin {
@@ -7,7 +7,7 @@ export class ReportNumberPlugin {
* @param property
* The report number property.
*/
- constructor(property: IStringProperty) {
+ constructor(property: StringProperty) {
// property.setValue(`${ crypto.randomUUID().substring(0, 6) }`);
}
diff --git a/src/cti_authoring_tool/src/assets/configuration/properties/Activity.ts b/src/cti_authoring_tool/src/assets/configuration/properties/Activity.ts
index 346927c..8731a2d 100644
--- a/src/cti_authoring_tool/src/assets/configuration/properties/Activity.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/properties/Activity.ts
@@ -1,4 +1,4 @@
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
+import { PropertyType } from "@/assets/scripts/PageEditor";
export const Activity = {
id: "activity",
diff --git a/src/cti_authoring_tool/src/assets/configuration/properties/Artifact.ts b/src/cti_authoring_tool/src/assets/configuration/properties/Artifact.ts
index cd7d8d2..4e1115f 100644
--- a/src/cti_authoring_tool/src/assets/configuration/properties/Artifact.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/properties/Artifact.ts
@@ -1,4 +1,4 @@
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
+import { PropertyType } from "@/assets/scripts/PageEditor";
export const Artifact = {
id: "artifact",
diff --git a/src/cti_authoring_tool/src/assets/configuration/properties/Assessment.ts b/src/cti_authoring_tool/src/assets/configuration/properties/Assessment.ts
index 129ef87..cdc93bd 100644
--- a/src/cti_authoring_tool/src/assets/configuration/properties/Assessment.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/properties/Assessment.ts
@@ -1,7 +1,8 @@
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
+import { PropertyType } from "@/assets/scripts/PageEditor";
export const Assessment = {
id: "assessment",
name: "Assessment",
+ path: "*.assessment",
type: PropertyType.String
}
diff --git a/src/cti_authoring_tool/src/assets/configuration/properties/Attribution.ts b/src/cti_authoring_tool/src/assets/configuration/properties/Attribution.ts
index ab34b5a..9adf3bb 100644
--- a/src/cti_authoring_tool/src/assets/configuration/properties/Attribution.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/properties/Attribution.ts
@@ -1,4 +1,4 @@
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
+import { PropertyType } from "@/assets/scripts/PageEditor";
export const Attribution = {
id: "attribution",
diff --git a/src/cti_authoring_tool/src/assets/configuration/properties/Control.ts b/src/cti_authoring_tool/src/assets/configuration/properties/Control.ts
index 25af174..5341be7 100644
--- a/src/cti_authoring_tool/src/assets/configuration/properties/Control.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/properties/Control.ts
@@ -1,4 +1,4 @@
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
+import { PropertyType } from "@/assets/scripts/PageEditor";
export const Control = {
id: "control",
diff --git a/src/cti_authoring_tool/src/assets/configuration/properties/Criticality.ts b/src/cti_authoring_tool/src/assets/configuration/properties/Criticality.ts
index b1615ad..48066b3 100644
--- a/src/cti_authoring_tool/src/assets/configuration/properties/Criticality.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/properties/Criticality.ts
@@ -1,8 +1,9 @@
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
+import { PropertyType } from "@/assets/scripts/PageEditor";
export const Criticality = {
id: "criticality",
name: "Criticality",
+ path: "*.criticality",
type: PropertyType.Enum,
options: [
{ id: "fysa", text: "FYSA", value: "fysa" },
diff --git a/src/cti_authoring_tool/src/assets/configuration/properties/CveCvssScore.ts b/src/cti_authoring_tool/src/assets/configuration/properties/CveCvssScore.ts
index 792ba57..aa92f3e 100644
--- a/src/cti_authoring_tool/src/assets/configuration/properties/CveCvssScore.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/properties/CveCvssScore.ts
@@ -1,4 +1,4 @@
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
+import { PropertyType } from "@/assets/scripts/PageEditor";
export const CveCvssScore = {
id: "cve_cvss_score",
diff --git a/src/cti_authoring_tool/src/assets/configuration/properties/CveNumber.ts b/src/cti_authoring_tool/src/assets/configuration/properties/CveNumber.ts
index 7e17d9d..ee6d15d 100644
--- a/src/cti_authoring_tool/src/assets/configuration/properties/CveNumber.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/properties/CveNumber.ts
@@ -1,4 +1,4 @@
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
+import { PropertyType } from "@/assets/scripts/PageEditor";
export const CveNumber = {
id: "cve_number",
diff --git a/src/cti_authoring_tool/src/assets/configuration/properties/CvePatchApplied.ts b/src/cti_authoring_tool/src/assets/configuration/properties/CvePatchApplied.ts
index bc54a82..1b08f38 100644
--- a/src/cti_authoring_tool/src/assets/configuration/properties/CvePatchApplied.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/properties/CvePatchApplied.ts
@@ -1,4 +1,4 @@
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
+import { PropertyType } from "@/assets/scripts/PageEditor";
export const CvePatchApplied = {
id: "cve_patch_applied",
diff --git a/src/cti_authoring_tool/src/assets/configuration/properties/CvePatchAvailable.ts b/src/cti_authoring_tool/src/assets/configuration/properties/CvePatchAvailable.ts
index 07a2994..c70da02 100644
--- a/src/cti_authoring_tool/src/assets/configuration/properties/CvePatchAvailable.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/properties/CvePatchAvailable.ts
@@ -1,4 +1,4 @@
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
+import { PropertyType } from "@/assets/scripts/PageEditor";
export const CvePatchAvailable = {
id: "cve_patch_available",
diff --git a/src/cti_authoring_tool/src/assets/configuration/properties/CveRemediation.ts b/src/cti_authoring_tool/src/assets/configuration/properties/CveRemediation.ts
index e6ef07e..ded4ae7 100644
--- a/src/cti_authoring_tool/src/assets/configuration/properties/CveRemediation.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/properties/CveRemediation.ts
@@ -1,4 +1,4 @@
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
+import { PropertyType } from "@/assets/scripts/PageEditor";
export const CveRemediation = {
id: "cve_remediation",
diff --git a/src/cti_authoring_tool/src/assets/configuration/properties/Cves.ts b/src/cti_authoring_tool/src/assets/configuration/properties/Cves.ts
index b495807..ff00d4a 100644
--- a/src/cti_authoring_tool/src/assets/configuration/properties/Cves.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/properties/Cves.ts
@@ -2,20 +2,25 @@ import { CveNumber } from "./CveNumber";
import { Attribution } from "./Attribution";
import { CveCvssScore } from "./CveCvssScore";
import { DateOfReport } from "./DateOfReport";
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
+import { PropertyType } from "@/assets/scripts/PageEditor";
import { CveRemediation } from "./CveRemediation";
import { CvePatchApplied } from "./CvePatchApplied";
import { CvePatchAvailable } from "./CvePatchAvailable";
+import { ImportCSVPlugin } from "../plugins/ImportCSVPlugin";
export const Cves = {
id: "cves",
name: "Common Vulnerabilities and Exposures (CVE)",
+ path: "*.iocs.cves",
type: PropertyType.ComplexTable,
layout: {
summary: "{{ attribution }}\n**{{ cve_number }}**",
rows: 4,
cols: 2
},
+ plugins: [
+ { module: ImportCSVPlugin }
+ ],
properties: [
{
...Attribution,
diff --git a/src/cti_authoring_tool/src/assets/configuration/properties/DateOfReport.ts b/src/cti_authoring_tool/src/assets/configuration/properties/DateOfReport.ts
index 65c22c5..fc5422b 100644
--- a/src/cti_authoring_tool/src/assets/configuration/properties/DateOfReport.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/properties/DateOfReport.ts
@@ -1,4 +1,4 @@
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
+import { PropertyType } from "@/assets/scripts/PageEditor";
export const DateOfReport = {
id: "date_of_report",
diff --git a/src/cti_authoring_tool/src/assets/configuration/properties/DateReported.ts b/src/cti_authoring_tool/src/assets/configuration/properties/DateReported.ts
index 708b218..c136bcc 100644
--- a/src/cti_authoring_tool/src/assets/configuration/properties/DateReported.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/properties/DateReported.ts
@@ -1,4 +1,4 @@
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
+import { PropertyType } from "@/assets/scripts/PageEditor";
export const DateReported = {
id: "date_reported",
diff --git a/src/cti_authoring_tool/src/assets/configuration/properties/Defend.ts b/src/cti_authoring_tool/src/assets/configuration/properties/Defend.ts
index c82960a..c745a89 100644
--- a/src/cti_authoring_tool/src/assets/configuration/properties/Defend.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/properties/Defend.ts
@@ -1,4 +1,4 @@
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
+import { PropertyType } from "@/assets/scripts/PageEditor";
export const Defend = {
id: "defend",
diff --git a/src/cti_authoring_tool/src/assets/configuration/properties/ExecutiveSummary.ts b/src/cti_authoring_tool/src/assets/configuration/properties/ExecutiveSummary.ts
index b18b7bc..aa433e4 100644
--- a/src/cti_authoring_tool/src/assets/configuration/properties/ExecutiveSummary.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/properties/ExecutiveSummary.ts
@@ -1,7 +1,8 @@
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
+import { PropertyType } from "@/assets/scripts/PageEditor";
export const ExecutiveSummary = {
id: "executive_summary",
name: "Executive Summary",
+ path: "*.executive_summary",
type: PropertyType.String
}
diff --git a/src/cti_authoring_tool/src/assets/configuration/properties/FirstObserved.ts b/src/cti_authoring_tool/src/assets/configuration/properties/FirstObserved.ts
index 49663ef..80cf4ee 100644
--- a/src/cti_authoring_tool/src/assets/configuration/properties/FirstObserved.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/properties/FirstObserved.ts
@@ -1,4 +1,4 @@
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
+import { PropertyType } from "@/assets/scripts/PageEditor";
export const FirstObserved = {
id: "first_observed",
diff --git a/src/cti_authoring_tool/src/assets/configuration/properties/IndicatorAnalysis.ts b/src/cti_authoring_tool/src/assets/configuration/properties/IndicatorAnalysis.ts
index cff4709..ebebc28 100644
--- a/src/cti_authoring_tool/src/assets/configuration/properties/IndicatorAnalysis.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/properties/IndicatorAnalysis.ts
@@ -1,7 +1,8 @@
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
+import { PropertyType } from "@/assets/scripts/PageEditor";
export const IndicatorAnalysis = {
id: "indicator_analysis",
+ path: "*.indicator_analysis",
name: "Indicator Analysis",
type: PropertyType.String,
}
diff --git a/src/cti_authoring_tool/src/assets/configuration/properties/Infrastructure.ts b/src/cti_authoring_tool/src/assets/configuration/properties/Infrastructure.ts
index 8ed86ea..2375e56 100644
--- a/src/cti_authoring_tool/src/assets/configuration/properties/Infrastructure.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/properties/Infrastructure.ts
@@ -1,4 +1,4 @@
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
+import { PropertyType } from "@/assets/scripts/PageEditor";
export const Infrastructure = {
id: "infrastructure",
diff --git a/src/cti_authoring_tool/src/assets/configuration/properties/IntelligenceRequirement.ts b/src/cti_authoring_tool/src/assets/configuration/properties/IntelligenceRequirement.ts
index 2f29f2a..eb8e1d9 100644
--- a/src/cti_authoring_tool/src/assets/configuration/properties/IntelligenceRequirement.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/properties/IntelligenceRequirement.ts
@@ -1,4 +1,4 @@
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
+import { PropertyType } from "@/assets/scripts/PageEditor";
export const IntelligenceRequirement = {
id: "intelligence_requirement",
diff --git a/src/cti_authoring_tool/src/assets/configuration/properties/IntelligenceRequirements.ts b/src/cti_authoring_tool/src/assets/configuration/properties/IntelligenceRequirements.ts
new file mode 100644
index 0000000..c3c5e11
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/configuration/properties/IntelligenceRequirements.ts
@@ -0,0 +1,23 @@
+import { PropertyType } from "@/assets/scripts/PageEditor";
+import { ImportCSVPlugin } from "../plugins/ImportCSVPlugin";
+import { IntelligenceRequirement } from "./IntelligenceRequirement";
+
+export const IntelligenceRequirements = {
+ id: "intelligence_requirements",
+ name: "Intelligence Requirements",
+ path: "*.intelligence_requirements",
+ type: PropertyType.BasicTable,
+ layout: {
+ cols: 1,
+ },
+ plugins: [
+ { module: ImportCSVPlugin }
+ ],
+ properties: [
+ {
+ ...IntelligenceRequirement,
+ row: 0,
+ col: 1
+ }
+ ]
+}
diff --git a/src/cti_authoring_tool/src/assets/configuration/properties/InternalTelemetry.ts b/src/cti_authoring_tool/src/assets/configuration/properties/InternalTelemetry.ts
index 4c40b79..780bfa6 100644
--- a/src/cti_authoring_tool/src/assets/configuration/properties/InternalTelemetry.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/properties/InternalTelemetry.ts
@@ -1,4 +1,4 @@
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
+import { PropertyType } from "@/assets/scripts/PageEditor";
export const InternalTelemetry = {
id: "internal_telemetry",
diff --git a/src/cti_authoring_tool/src/assets/configuration/properties/InternalTelemetryTable.ts b/src/cti_authoring_tool/src/assets/configuration/properties/InternalTelemetryTable.ts
new file mode 100644
index 0000000..a0fa695
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/configuration/properties/InternalTelemetryTable.ts
@@ -0,0 +1,23 @@
+import { PropertyType } from "@/assets/scripts/PageEditor";
+import { ImportCSVPlugin } from "../plugins/ImportCSVPlugin";
+import { InternalTelemetry } from "./InternalTelemetry";
+
+export const InternalTelemetryTable = {
+ id: "internal_telemetry",
+ name: "Internal Telemetry",
+ path: "*.data_sources.internal_telemetry",
+ type: PropertyType.BasicTable,
+ layout: {
+ cols: 1,
+ },
+ plugins: [
+ { module: ImportCSVPlugin }
+ ],
+ properties: [
+ {
+ ...InternalTelemetry,
+ row: 0,
+ col: 1
+ }
+ ]
+}
diff --git a/src/cti_authoring_tool/src/assets/configuration/properties/IocAssociatedFileHash.ts b/src/cti_authoring_tool/src/assets/configuration/properties/IocAssociatedFileHash.ts
index 2a0fb37..026b960 100644
--- a/src/cti_authoring_tool/src/assets/configuration/properties/IocAssociatedFileHash.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/properties/IocAssociatedFileHash.ts
@@ -1,4 +1,4 @@
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
+import { PropertyType } from "@/assets/scripts/PageEditor";
export const IocAssociateFileHash = {
id: "ioc_associated_file_hash",
diff --git a/src/cti_authoring_tool/src/assets/configuration/properties/IocMalwareDescription.ts b/src/cti_authoring_tool/src/assets/configuration/properties/IocMalwareDescription.ts
index c6b400a..5f4d068 100644
--- a/src/cti_authoring_tool/src/assets/configuration/properties/IocMalwareDescription.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/properties/IocMalwareDescription.ts
@@ -1,4 +1,4 @@
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
+import { PropertyType } from "@/assets/scripts/PageEditor";
export const IocMalwareDescription = {
id: "ioc_malware_description",
diff --git a/src/cti_authoring_tool/src/assets/configuration/properties/IocMalwareHash.ts b/src/cti_authoring_tool/src/assets/configuration/properties/IocMalwareHash.ts
index 689413a..30bb2df 100644
--- a/src/cti_authoring_tool/src/assets/configuration/properties/IocMalwareHash.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/properties/IocMalwareHash.ts
@@ -1,4 +1,4 @@
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
+import { PropertyType } from "@/assets/scripts/PageEditor";
export const IocMalwareHash = {
id: "ioc_malware_hash",
diff --git a/src/cti_authoring_tool/src/assets/configuration/properties/IocMalwareHashType.ts b/src/cti_authoring_tool/src/assets/configuration/properties/IocMalwareHashType.ts
index 7482a13..c84386c 100644
--- a/src/cti_authoring_tool/src/assets/configuration/properties/IocMalwareHashType.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/properties/IocMalwareHashType.ts
@@ -1,4 +1,4 @@
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
+import { PropertyType } from "@/assets/scripts/PageEditor";
export const IocMalwareHashType = {
id: "ioc_malware_hash_type",
diff --git a/src/cti_authoring_tool/src/assets/configuration/properties/IocMalwareName.ts b/src/cti_authoring_tool/src/assets/configuration/properties/IocMalwareName.ts
index fb5f7fa..a37f453 100644
--- a/src/cti_authoring_tool/src/assets/configuration/properties/IocMalwareName.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/properties/IocMalwareName.ts
@@ -1,4 +1,4 @@
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
+import { PropertyType } from "@/assets/scripts/PageEditor";
export const IocMalwareName = {
id: "ioc_malware_name",
diff --git a/src/cti_authoring_tool/src/assets/configuration/properties/IocMalwareSandbox.ts b/src/cti_authoring_tool/src/assets/configuration/properties/IocMalwareSandbox.ts
index f78550d..9cee917 100644
--- a/src/cti_authoring_tool/src/assets/configuration/properties/IocMalwareSandbox.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/properties/IocMalwareSandbox.ts
@@ -1,4 +1,4 @@
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
+import { PropertyType } from "@/assets/scripts/PageEditor";
export const IocMalwareSandbox = {
id: "ioc_malware_sandbox",
diff --git a/src/cti_authoring_tool/src/assets/configuration/properties/IocsMalware.ts b/src/cti_authoring_tool/src/assets/configuration/properties/IocsMalware.ts
index b2f720e..9ebe92f 100644
--- a/src/cti_authoring_tool/src/assets/configuration/properties/IocsMalware.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/properties/IocsMalware.ts
@@ -1,22 +1,27 @@
import { Timestamp } from "./Timestamp";
import { Attribution } from "./Attribution";
-import { IocMalwareDescription } from "./IocMalwareDescription";
+import { PropertyType } from "@/assets/scripts/PageEditor";
import { IocMalwareHash } from "./IocMalwareHash";
import { IocMalwareName } from "./IocMalwareName";
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
+import { ImportCSVPlugin } from "../plugins/ImportCSVPlugin";
import { IocMalwareSandbox } from "./IocMalwareSandbox";
import { IocMalwareHashType } from "./IocMalwareHashType";
import { IocAssociateFileHash } from "./IocAssociatedFileHash";
+import { IocMalwareDescription } from "./IocMalwareDescription";
export const IocsMalware = {
id: "ioc_malware",
name: "Malware",
+ path: "*.iocs.malware",
type: PropertyType.ComplexTable,
layout: {
summary: "{{ attribution }}\n**{{ ioc_malware_name }}**",
rows: 5,
cols: 10
},
+ plugins: [
+ { module: ImportCSVPlugin }
+ ],
properties: [
{
...Attribution,
diff --git a/src/cti_authoring_tool/src/assets/configuration/properties/IocsNetwork.ts b/src/cti_authoring_tool/src/assets/configuration/properties/IocsNetwork.ts
index 1ee8da9..d2312d4 100644
--- a/src/cti_authoring_tool/src/assets/configuration/properties/IocsNetwork.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/properties/IocsNetwork.ts
@@ -1,19 +1,24 @@
import { Artifact } from "./Artifact";
import { Attribution } from "./Attribution";
import { LastObserved } from "./LastObserved";
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
+import { PropertyType } from "@/assets/scripts/PageEditor";
import { FirstObserved } from "./FirstObserved";
+import { ImportCSVPlugin } from "../plugins/ImportCSVPlugin";
import { NetworkIntrusionPhase } from "./NetworkIntrusionPhase";
export const IocsNetwork = {
id: "ioc_network",
name: "Network Indicators",
+ path: "*.iocs.network",
type: PropertyType.ComplexTable,
layout: {
summary: "{{ attribution }}\n**{{ artifact }}**",
cols: 2,
rows: 3
},
+ plugins: [
+ { module: ImportCSVPlugin }
+ ],
properties: [
{
...Attribution,
diff --git a/src/cti_authoring_tool/src/assets/configuration/properties/KeyIntelligenceGaps.ts b/src/cti_authoring_tool/src/assets/configuration/properties/KeyIntelligenceGaps.ts
index 685eda5..d65aada 100644
--- a/src/cti_authoring_tool/src/assets/configuration/properties/KeyIntelligenceGaps.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/properties/KeyIntelligenceGaps.ts
@@ -1,7 +1,8 @@
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
+import { PropertyType } from "@/assets/scripts/PageEditor";
export const KeyIntelligenceGaps = {
- id: "key_intelligence_gaps",
+ id: "intelligence_gaps",
name: "Key Intelligence Gaps",
+ path: "*.intelligence_gaps",
type: PropertyType.String
}
diff --git a/src/cti_authoring_tool/src/assets/configuration/properties/KeyPoints.ts b/src/cti_authoring_tool/src/assets/configuration/properties/KeyPoints.ts
index eaea2b3..927b5ec 100644
--- a/src/cti_authoring_tool/src/assets/configuration/properties/KeyPoints.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/properties/KeyPoints.ts
@@ -1,7 +1,8 @@
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
+import { PropertyType } from "@/assets/scripts/PageEditor";
export const KeyPoints = {
id: "key_points",
name: "Key Points",
+ path: "*.key_points",
type: PropertyType.String
}
diff --git a/src/cti_authoring_tool/src/assets/configuration/properties/LastObserved.ts b/src/cti_authoring_tool/src/assets/configuration/properties/LastObserved.ts
index 15b66d0..45e3470 100644
--- a/src/cti_authoring_tool/src/assets/configuration/properties/LastObserved.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/properties/LastObserved.ts
@@ -1,4 +1,4 @@
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
+import { PropertyType } from "@/assets/scripts/PageEditor";
export const LastObserved = {
id: "last_observed",
diff --git a/src/cti_authoring_tool/src/assets/configuration/properties/LocationGranular.ts b/src/cti_authoring_tool/src/assets/configuration/properties/LocationGranular.ts
index 521534e..5e67e46 100644
--- a/src/cti_authoring_tool/src/assets/configuration/properties/LocationGranular.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/properties/LocationGranular.ts
@@ -1,4 +1,4 @@
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
+import { PropertyType } from "@/assets/scripts/PageEditor";
export const LocationGranular = {
id: "location",
diff --git a/src/cti_authoring_tool/src/assets/configuration/properties/LocationRegion.ts b/src/cti_authoring_tool/src/assets/configuration/properties/LocationRegion.ts
index 3186625..f917d5e 100644
--- a/src/cti_authoring_tool/src/assets/configuration/properties/LocationRegion.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/properties/LocationRegion.ts
@@ -3,7 +3,7 @@
* For more information, refer to: https://wits.worldbank.org/wits/wits/witshelp/content/codes/country_codes.htm
*/
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
+import { PropertyType } from "@/assets/scripts/PageEditor";
export const LocationRegion = {
id: "location",
diff --git a/src/cti_authoring_tool/src/assets/configuration/properties/MitreAttackTable.ts b/src/cti_authoring_tool/src/assets/configuration/properties/MitreAttackTable.ts
index e2efe7e..de7ab4f 100644
--- a/src/cti_authoring_tool/src/assets/configuration/properties/MitreAttackTable.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/properties/MitreAttackTable.ts
@@ -4,18 +4,23 @@ import { Tactic } from "./Tactic";
import { Procedure } from "./Procedure";
import { Techniques } from "./Technique";
import { Attribution } from "./Attribution";
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
+import { PropertyType } from "@/assets/scripts/PageEditor";
import { SubTechniques } from "./SubTechnique";
+import { ImportCSVPlugin } from "../plugins/ImportCSVPlugin";
export const MitreAttackTable = {
id: "mitre_attack_table",
name: "MITRE ATT&CK Table",
+ path: "*.mitre_attack_table",
type: PropertyType.ComplexTable,
layout: {
summary: "{{ attribution }}\n**{{ tactic }} :: {{ technique }}**",
rows: 5,
cols: 2
},
+ plugins: [
+ { module: ImportCSVPlugin }
+ ],
properties: [
{
...Attribution,
diff --git a/src/cti_authoring_tool/src/assets/configuration/properties/MitreAttackTableSimple.ts b/src/cti_authoring_tool/src/assets/configuration/properties/MitreAttackTableSimple.ts
index 9398e32..3abdca9 100644
--- a/src/cti_authoring_tool/src/assets/configuration/properties/MitreAttackTableSimple.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/properties/MitreAttackTableSimple.ts
@@ -2,8 +2,9 @@ import { Defend } from "./Defend";
import { Tactic } from "./Tactic";
import { Procedure } from "./Procedure";
import { Techniques } from "./Technique";
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
+import { PropertyType } from "@/assets/scripts/PageEditor";
import { SubTechniques } from "./SubTechnique";
+import { ImportCSVPlugin } from "../plugins/ImportCSVPlugin";
export const MitreAttackTableSimple = {
id: "mitre_attack_table",
@@ -14,6 +15,9 @@ export const MitreAttackTableSimple = {
rows: 4,
cols: 2
},
+ plugins: [
+ { module: ImportCSVPlugin }
+ ],
properties: [
{
...Tactic,
diff --git a/src/cti_authoring_tool/src/assets/configuration/properties/NetworkIntrusionPhase.ts b/src/cti_authoring_tool/src/assets/configuration/properties/NetworkIntrusionPhase.ts
index b11dbfa..a217dfc 100644
--- a/src/cti_authoring_tool/src/assets/configuration/properties/NetworkIntrusionPhase.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/properties/NetworkIntrusionPhase.ts
@@ -1,4 +1,4 @@
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
+import { PropertyType } from "@/assets/scripts/PageEditor";
export const NetworkIntrusionPhase = {
id: "network_intrusion_phase",
diff --git a/src/cti_authoring_tool/src/assets/configuration/properties/Outlook.ts b/src/cti_authoring_tool/src/assets/configuration/properties/Outlook.ts
index bff0f3c..2303a84 100644
--- a/src/cti_authoring_tool/src/assets/configuration/properties/Outlook.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/properties/Outlook.ts
@@ -1,7 +1,8 @@
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
+import { PropertyType } from "@/assets/scripts/PageEditor";
export const Outlook = {
id: "outlook",
name: "Outlook",
+ path: "*.outlook",
type: PropertyType.String
}
diff --git a/src/cti_authoring_tool/src/assets/configuration/properties/Procedure.ts b/src/cti_authoring_tool/src/assets/configuration/properties/Procedure.ts
index 018da14..a23d059 100644
--- a/src/cti_authoring_tool/src/assets/configuration/properties/Procedure.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/properties/Procedure.ts
@@ -1,4 +1,4 @@
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
+import { PropertyType } from "@/assets/scripts/PageEditor";
export const Procedure = {
id: "procedure",
diff --git a/src/cti_authoring_tool/src/assets/configuration/properties/ReportCitations.ts b/src/cti_authoring_tool/src/assets/configuration/properties/ReportCitations.ts
index 54cce55..11f3d85 100644
--- a/src/cti_authoring_tool/src/assets/configuration/properties/ReportCitations.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/properties/ReportCitations.ts
@@ -1,12 +1,17 @@
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
+import { PropertyType } from "@/assets/scripts/PageEditor";
+import { ImportCSVPlugin } from "../plugins/ImportCSVPlugin";
export const ReportCitations = {
id: "report_citations",
name: "Report Citations",
+ path: "*.data_sources.report_citations",
type: PropertyType.BasicTable,
layout: {
cols: 3
},
+ plugins: [
+ { module: ImportCSVPlugin }
+ ],
properties: [
{
id: "description",
diff --git a/src/cti_authoring_tool/src/assets/configuration/properties/ReportNumber.ts b/src/cti_authoring_tool/src/assets/configuration/properties/ReportNumber.ts
index cc32fc0..1d8e6f1 100644
--- a/src/cti_authoring_tool/src/assets/configuration/properties/ReportNumber.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/properties/ReportNumber.ts
@@ -1,11 +1,12 @@
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
+import { PropertyType } from "@/assets/scripts/PageEditor";
import { ReportNumberPlugin } from "../plugins/ReportNumberPlugin";
export const ReportNumber = {
id: "report_number",
name: "Report Number",
+ path: "*.report_number",
type: PropertyType.String,
plugins: [
- { plugin: ReportNumberPlugin }
+ { module: ReportNumberPlugin }
]
}
diff --git a/src/cti_authoring_tool/src/assets/configuration/properties/ReportTitle.ts b/src/cti_authoring_tool/src/assets/configuration/properties/ReportTitle.ts
index 44548c9..4dff828 100644
--- a/src/cti_authoring_tool/src/assets/configuration/properties/ReportTitle.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/properties/ReportTitle.ts
@@ -1,8 +1,9 @@
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
+import { PropertyType } from "@/assets/scripts/PageEditor";
export const ReportTitle = {
id: "report_title",
name: "Report Title",
+ path: "*.report_title",
type: PropertyType.String,
is_primary: true
}
diff --git a/src/cti_authoring_tool/src/assets/configuration/properties/Sector.ts b/src/cti_authoring_tool/src/assets/configuration/properties/Sector.ts
index 4b0d41d..99e261c 100644
--- a/src/cti_authoring_tool/src/assets/configuration/properties/Sector.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/properties/Sector.ts
@@ -3,7 +3,7 @@
* For more information, refer to: https://www.bls.gov/iag/tgs/iag_index_naics.htm
*/
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
+import { PropertyType } from "@/assets/scripts/PageEditor";
export const Sector = {
id: "sector",
diff --git a/src/cti_authoring_tool/src/assets/configuration/properties/Sensitivity.ts b/src/cti_authoring_tool/src/assets/configuration/properties/Sensitivity.ts
index 2cbc28c..9b91522 100644
--- a/src/cti_authoring_tool/src/assets/configuration/properties/Sensitivity.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/properties/Sensitivity.ts
@@ -1,7 +1,8 @@
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
+import { PropertyType } from "@/assets/scripts/PageEditor";
export const Sensitivity = {
id: "sensitivity",
- name: "Sensitivity",
+ name: "Sensitivity",
+ path: "*.sensitivity",
type: PropertyType.String
}
diff --git a/src/cti_authoring_tool/src/assets/configuration/properties/SignatureDescription.ts b/src/cti_authoring_tool/src/assets/configuration/properties/SignatureDescription.ts
index 85a2201..8fbf375 100644
--- a/src/cti_authoring_tool/src/assets/configuration/properties/SignatureDescription.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/properties/SignatureDescription.ts
@@ -1,4 +1,4 @@
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
+import { PropertyType } from "@/assets/scripts/PageEditor";
export const SignatureDescription = {
id: "signature_description",
diff --git a/src/cti_authoring_tool/src/assets/configuration/properties/Signatures.ts b/src/cti_authoring_tool/src/assets/configuration/properties/Signatures.ts
index 48f88d5..5503122 100644
--- a/src/cti_authoring_tool/src/assets/configuration/properties/Signatures.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/properties/Signatures.ts
@@ -1,17 +1,22 @@
import { Attribution } from "./Attribution";
import { IocMalwareName } from "./IocMalwareName";
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
+import { PropertyType } from "@/assets/scripts/PageEditor";
import { SignatureDescription } from "./SignatureDescription";
+import { ImportCSVPlugin } from "../plugins/ImportCSVPlugin";
export const Signatures = {
id: "signatures",
name: "Signatures",
+ path: "*.signatures",
type: PropertyType.ComplexTable,
layout: {
summary: "{{ attribution }}\n**{{ ioc_malware_name }}**",
rows: 2,
cols: 2
},
+ plugins: [
+ { module: ImportCSVPlugin }
+ ],
properties: [
{
...Attribution,
diff --git a/src/cti_authoring_tool/src/assets/configuration/properties/SubTechnique.ts b/src/cti_authoring_tool/src/assets/configuration/properties/SubTechnique.ts
index bfc9e56..a06698c 100644
--- a/src/cti_authoring_tool/src/assets/configuration/properties/SubTechnique.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/properties/SubTechnique.ts
@@ -1,4 +1,4 @@
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
+import { PropertyType } from "@/assets/scripts/PageEditor";
export const SubTechniques = {
id: "sub_technique",
diff --git a/src/cti_authoring_tool/src/assets/configuration/properties/SystemArtifacts.ts b/src/cti_authoring_tool/src/assets/configuration/properties/SystemArtifacts.ts
index 56ab1d7..0710815 100644
--- a/src/cti_authoring_tool/src/assets/configuration/properties/SystemArtifacts.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/properties/SystemArtifacts.ts
@@ -1,20 +1,25 @@
import { Tactic } from "./Tactic";
import { Artifact } from "./Artifact";
import { Attribution } from "./Attribution";
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
+import { PropertyType } from "@/assets/scripts/PageEditor";
import { LastObserved } from "./LastObserved";
import { FirstObserved } from "./FirstObserved";
import { SystemDetails } from "./SystemDetails";
+import { ImportCSVPlugin } from "../plugins/ImportCSVPlugin";
export const SystemArtifacts = {
id: "system_artifacts",
name: "System Artifacts",
+ path: "*.iocs.system_artifacts",
type: PropertyType.ComplexTable,
layout: {
summary: "{{ attribution }}\n**{{ artifact }}**",
rows: 4,
cols: 2
},
+ plugins: [
+ { module: ImportCSVPlugin }
+ ],
properties: [
{
...Attribution,
diff --git a/src/cti_authoring_tool/src/assets/configuration/properties/SystemDetails.ts b/src/cti_authoring_tool/src/assets/configuration/properties/SystemDetails.ts
index 39f302b..bba14de 100644
--- a/src/cti_authoring_tool/src/assets/configuration/properties/SystemDetails.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/properties/SystemDetails.ts
@@ -1,4 +1,4 @@
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
+import { PropertyType } from "@/assets/scripts/PageEditor";
export const SystemDetails = {
id: "system_details",
diff --git a/src/cti_authoring_tool/src/assets/configuration/properties/Tactic.ts b/src/cti_authoring_tool/src/assets/configuration/properties/Tactic.ts
index 84c6b14..4d4c010 100644
--- a/src/cti_authoring_tool/src/assets/configuration/properties/Tactic.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/properties/Tactic.ts
@@ -1,4 +1,4 @@
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
+import { PropertyType } from "@/assets/scripts/PageEditor";
export const Tactic = {
id: "tactic",
diff --git a/src/cti_authoring_tool/src/assets/configuration/properties/Technique.ts b/src/cti_authoring_tool/src/assets/configuration/properties/Technique.ts
index 2a26ffb..4d55437 100644
--- a/src/cti_authoring_tool/src/assets/configuration/properties/Technique.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/properties/Technique.ts
@@ -1,4 +1,4 @@
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
+import { PropertyType } from "@/assets/scripts/PageEditor";
export const Techniques = {
id: "technique",
diff --git a/src/cti_authoring_tool/src/assets/configuration/properties/ThreatActorAliases.ts b/src/cti_authoring_tool/src/assets/configuration/properties/ThreatActorAliases.ts
index 523ff93..22eff0b 100644
--- a/src/cti_authoring_tool/src/assets/configuration/properties/ThreatActorAliases.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/properties/ThreatActorAliases.ts
@@ -1,4 +1,4 @@
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
+import { PropertyType } from "@/assets/scripts/PageEditor";
export const ThreatActorAliases = {
id : "threat_actor_aliases",
diff --git a/src/cti_authoring_tool/src/assets/configuration/properties/ThreatActorAttribution.ts b/src/cti_authoring_tool/src/assets/configuration/properties/ThreatActorAttribution.ts
index 0812c12..eb118df 100644
--- a/src/cti_authoring_tool/src/assets/configuration/properties/ThreatActorAttribution.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/properties/ThreatActorAttribution.ts
@@ -1,7 +1,8 @@
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
+import { PropertyType } from "@/assets/scripts/PageEditor";
export const ThreatActorAttribution = {
id: "threat_actor_attribution",
name: "Attribution",
+ path: "*.threat_actor.attribution",
type: PropertyType.String
}
diff --git a/src/cti_authoring_tool/src/assets/configuration/properties/ThreatActorAttributions.ts b/src/cti_authoring_tool/src/assets/configuration/properties/ThreatActorAttributions.ts
index 5b72f82..af577df 100644
--- a/src/cti_authoring_tool/src/assets/configuration/properties/ThreatActorAttributions.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/properties/ThreatActorAttributions.ts
@@ -1,6 +1,7 @@
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
+import { PropertyType } from "@/assets/scripts/PageEditor";
import { ThreatActorName } from "./ThreatActorName";
import { ThreatActorAliases } from "./ThreatActorAliases";
+import { ImportCSVPlugin } from "../plugins/ImportCSVPlugin";
export const ThreatActorAttributions = {
id: "threat_actors",
@@ -9,6 +10,9 @@ export const ThreatActorAttributions = {
layout: {
cols: 3,
},
+ plugins: [
+ { module: ImportCSVPlugin }
+ ],
properties: [
{
...ThreatActorName,
diff --git a/src/cti_authoring_tool/src/assets/configuration/properties/ThreatActorInfrastructure.ts b/src/cti_authoring_tool/src/assets/configuration/properties/ThreatActorInfrastructure.ts
index 5cd506e..7ab697c 100644
--- a/src/cti_authoring_tool/src/assets/configuration/properties/ThreatActorInfrastructure.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/properties/ThreatActorInfrastructure.ts
@@ -1,7 +1,8 @@
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
+import { PropertyType } from "@/assets/scripts/PageEditor";
export const ThreatActorInfrastructure = {
id: "threat_actor_infrastructure",
name: "Infrastructure",
+ path: "*.threat_actor.infrastructure",
type: PropertyType.String
}
diff --git a/src/cti_authoring_tool/src/assets/configuration/properties/ThreatActorMotivation.ts b/src/cti_authoring_tool/src/assets/configuration/properties/ThreatActorMotivation.ts
index 63ac8d6..19a2898 100644
--- a/src/cti_authoring_tool/src/assets/configuration/properties/ThreatActorMotivation.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/properties/ThreatActorMotivation.ts
@@ -1,4 +1,4 @@
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
+import { PropertyType } from "@/assets/scripts/PageEditor";
export const ThreatActorMotivation = {
id: "threat_actor_motivation",
diff --git a/src/cti_authoring_tool/src/assets/configuration/properties/ThreatActorName.ts b/src/cti_authoring_tool/src/assets/configuration/properties/ThreatActorName.ts
index 6437146..ac60957 100644
--- a/src/cti_authoring_tool/src/assets/configuration/properties/ThreatActorName.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/properties/ThreatActorName.ts
@@ -1,4 +1,4 @@
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
+import { PropertyType } from "@/assets/scripts/PageEditor";
export const ThreatActorName = {
id : "threat_actor_name",
diff --git a/src/cti_authoring_tool/src/assets/configuration/properties/ThreatActorSummary.ts b/src/cti_authoring_tool/src/assets/configuration/properties/ThreatActorSummary.ts
index e94ae55..7dd53d1 100644
--- a/src/cti_authoring_tool/src/assets/configuration/properties/ThreatActorSummary.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/properties/ThreatActorSummary.ts
@@ -1,7 +1,8 @@
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
+import { PropertyType } from "@/assets/scripts/PageEditor";
export const ThreatActorSummary = {
id: "threat_actor_summary",
name: "Threat Actor Summary",
+ path: "*.threat_actor.summary",
type: PropertyType.String
}
diff --git a/src/cti_authoring_tool/src/assets/configuration/properties/ThreatActorVictims.ts b/src/cti_authoring_tool/src/assets/configuration/properties/ThreatActorVictims.ts
index 6a09239..3f1df4c 100644
--- a/src/cti_authoring_tool/src/assets/configuration/properties/ThreatActorVictims.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/properties/ThreatActorVictims.ts
@@ -1,7 +1,8 @@
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
+import { PropertyType } from "@/assets/scripts/PageEditor";
export const ThreatActorVictims = {
id: "threat_actor_victims",
name: "Victims",
+ path: "*.threat_actor.victims",
type: PropertyType.String
}
diff --git a/src/cti_authoring_tool/src/assets/configuration/properties/ThreatActorsTtp.ts b/src/cti_authoring_tool/src/assets/configuration/properties/ThreatActorsTtp.ts
index 09db01d..2eb6375 100644
--- a/src/cti_authoring_tool/src/assets/configuration/properties/ThreatActorsTtp.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/properties/ThreatActorsTtp.ts
@@ -1,7 +1,8 @@
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
+import { PropertyType } from "@/assets/scripts/PageEditor";
export const ThreatActorsTtp = {
id: "threat_actor_ttp",
name: "Tactics, Techniques, & Procedures",
+ path: "*.threat_actor.ttp",
type: PropertyType.String
}
diff --git a/src/cti_authoring_tool/src/assets/configuration/properties/Timeline.ts b/src/cti_authoring_tool/src/assets/configuration/properties/Timeline.ts
index c96bad2..439a929 100644
--- a/src/cti_authoring_tool/src/assets/configuration/properties/Timeline.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/properties/Timeline.ts
@@ -1,20 +1,25 @@
import { Sector } from "./Sector";
import { Activity } from "./Activity";
import { Attribution } from "./Attribution";
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
+import { PropertyType } from "@/assets/scripts/PageEditor";
import { LocationRegion } from "./LocationRegion";
import { TimelineEndDate } from "./TimelineEndDate";
+import { ImportCSVPlugin } from "../plugins/ImportCSVPlugin";
import { TimelineStartDate } from "./TimelineStartDate";
export const Timeline = {
id: "timeline",
name: "Timeline of Activity",
+ path: "*.timeline",
type: PropertyType.ComplexTable,
layout: {
summary: "{{ attribution }}\n**{{ location }} :: {{ sector }}**",
rows: 4,
cols: 3
},
+ plugins: [
+ { module: ImportCSVPlugin }
+ ],
properties: [
{
...Attribution,
diff --git a/src/cti_authoring_tool/src/assets/configuration/properties/TimelineEndDate.ts b/src/cti_authoring_tool/src/assets/configuration/properties/TimelineEndDate.ts
index 04a95e9..186dda1 100644
--- a/src/cti_authoring_tool/src/assets/configuration/properties/TimelineEndDate.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/properties/TimelineEndDate.ts
@@ -1,7 +1,7 @@
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
+import { PropertyType } from "@/assets/scripts/PageEditor";
export const TimelineEndDate = {
- id: "end_data",
+ id: "end_date",
name: "End Date",
type: PropertyType.DateTime,
}
diff --git a/src/cti_authoring_tool/src/assets/configuration/properties/TimelineStartDate.ts b/src/cti_authoring_tool/src/assets/configuration/properties/TimelineStartDate.ts
index 97d0da7..91f7aaf 100644
--- a/src/cti_authoring_tool/src/assets/configuration/properties/TimelineStartDate.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/properties/TimelineStartDate.ts
@@ -1,7 +1,7 @@
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
+import { PropertyType } from "@/assets/scripts/PageEditor";
export const TimelineStartDate = {
- id: "start_data",
+ id: "start_date",
name: "Start Date",
type: PropertyType.DateTime,
}
diff --git a/src/cti_authoring_tool/src/assets/configuration/properties/Timestamp.ts b/src/cti_authoring_tool/src/assets/configuration/properties/Timestamp.ts
index 40d49d7..a46aff3 100644
--- a/src/cti_authoring_tool/src/assets/configuration/properties/Timestamp.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/properties/Timestamp.ts
@@ -1,4 +1,4 @@
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
+import { PropertyType } from "@/assets/scripts/PageEditor";
export const Timestamp = {
id: "timestamp",
diff --git a/src/cti_authoring_tool/src/assets/configuration/properties/TrafficLightProtocol.ts b/src/cti_authoring_tool/src/assets/configuration/properties/TrafficLightProtocol.ts
index dd5f580..fd19823 100644
--- a/src/cti_authoring_tool/src/assets/configuration/properties/TrafficLightProtocol.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/properties/TrafficLightProtocol.ts
@@ -1,8 +1,9 @@
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
+import { PropertyType } from "@/assets/scripts/PageEditor";
export const TrafficLightProtocol = {
id: "traffic_light_protocol",
name: "Traffic Light Protocol",
+ path: "*.traffic_light_protocol",
type: PropertyType.Enum,
options: [
{ id: "red", text: "Red", value: "red" },
diff --git a/src/cti_authoring_tool/src/assets/configuration/properties/VictimName.ts b/src/cti_authoring_tool/src/assets/configuration/properties/VictimName.ts
index 5663dac..68b5977 100644
--- a/src/cti_authoring_tool/src/assets/configuration/properties/VictimName.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/properties/VictimName.ts
@@ -1,4 +1,4 @@
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
+import { PropertyType } from "@/assets/scripts/PageEditor";
export const VictimName = {
id: "victim_name",
diff --git a/src/cti_authoring_tool/src/assets/configuration/properties/Victims.ts b/src/cti_authoring_tool/src/assets/configuration/properties/Victims.ts
index 03f2f99..5e6ec36 100644
--- a/src/cti_authoring_tool/src/assets/configuration/properties/Victims.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/properties/Victims.ts
@@ -1,19 +1,24 @@
import { Sector } from "./Sector";
import { VictimName } from "./VictimName";
import { DateReported } from "./DateReported";
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
+import { PropertyType } from "@/assets/scripts/PageEditor";
import { LocationRegion } from "./LocationRegion";
import { LocationGranular } from "./LocationGranular";
+import { ImportCSVPlugin } from "../plugins/ImportCSVPlugin";
export const Victims = {
id: "victims",
name: "Victims",
+ path: "*.victims",
type: PropertyType.ComplexTable,
layout: {
summary: "{{ victim_name }}\n**{{ location_region }} :: {{ sector }}**",
rows: 3,
cols: 2
},
+ plugins: [
+ { module: ImportCSVPlugin }
+ ],
properties: [
{
...VictimName,
diff --git a/src/cti_authoring_tool/src/assets/configuration/sections/AssessmentSection.ts b/src/cti_authoring_tool/src/assets/configuration/sections/AssessmentSection.ts
index b85e76c..4229dc1 100644
--- a/src/cti_authoring_tool/src/assets/configuration/sections/AssessmentSection.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/sections/AssessmentSection.ts
@@ -1,6 +1,7 @@
import { Assessment } from "../properties/Assessment";
export const AssessmentSection = {
+ id: "assessment",
name: "Assessment",
layout: {
rows: 7,
diff --git a/src/cti_authoring_tool/src/assets/configuration/sections/CampaignMetadataSection.ts b/src/cti_authoring_tool/src/assets/configuration/sections/CampaignMetadataSection.ts
index f8f3cbb..d2a67f8 100644
--- a/src/cti_authoring_tool/src/assets/configuration/sections/CampaignMetadataSection.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/sections/CampaignMetadataSection.ts
@@ -1,12 +1,15 @@
import { Sector } from "../properties/Sector";
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
+import { PropertyType } from "@/assets/scripts/PageEditor";
import { LocationRegion } from "../properties/LocationRegion";
+import { Infrastructure } from "../properties/Infrastructure";
+import { ImportCSVPlugin } from "../plugins/ImportCSVPlugin";
import { ThreatActorMotivation } from "../properties/ThreatActorMotivation";
import { ThreatActorAttributions } from "../properties/ThreatActorAttributions";
-import { Infrastructure } from "../properties/Infrastructure";
export const CampaignMetadataSection = {
+ id: "metadata",
name: "Metadata",
+ path: "*.metadata",
layout: {
rows: 5,
cols: 1
@@ -18,6 +21,7 @@ export const CampaignMetadataSection = {
col: 1
},
{
+ id: "victim_location",
name: "Victim Location",
type: PropertyType.BasicTable,
row: 2,
@@ -25,6 +29,9 @@ export const CampaignMetadataSection = {
layout: {
cols: 1
},
+ plugins: [
+ { module: ImportCSVPlugin }
+ ],
properties: [
{
...LocationRegion,
@@ -34,6 +41,7 @@ export const CampaignMetadataSection = {
]
},
{
+ id: "sectors",
name: "Sectors",
type: PropertyType.BasicTable,
row: 3,
@@ -41,6 +49,9 @@ export const CampaignMetadataSection = {
layout: {
cols: 1
},
+ plugins: [
+ { module: ImportCSVPlugin }
+ ],
properties: [
{
...Sector,
@@ -50,6 +61,7 @@ export const CampaignMetadataSection = {
]
},
{
+ id: "infrastructure_used",
name: "Infrastructure Used",
type: PropertyType.BasicTable,
row: 4,
@@ -57,6 +69,9 @@ export const CampaignMetadataSection = {
layout: {
cols: 1
},
+ plugins: [
+ { module: ImportCSVPlugin }
+ ],
properties: [
{
...Infrastructure,
@@ -66,6 +81,7 @@ export const CampaignMetadataSection = {
]
},
{
+ id: "threat_actor_motivation",
name: "Threat Actor Motivation",
type: PropertyType.BasicTable,
row: 5,
@@ -73,6 +89,9 @@ export const CampaignMetadataSection = {
layout: {
cols: 1,
},
+ plugins: [
+ { module: ImportCSVPlugin }
+ ],
properties: [
{
...ThreatActorMotivation,
diff --git a/src/cti_authoring_tool/src/assets/configuration/sections/DataSourcesSection.ts b/src/cti_authoring_tool/src/assets/configuration/sections/DataSourcesSection.ts
index ad26aa3..4af2cbd 100644
--- a/src/cti_authoring_tool/src/assets/configuration/sections/DataSourcesSection.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/sections/DataSourcesSection.ts
@@ -1,8 +1,8 @@
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
import { ReportCitations } from "../properties/ReportCitations";
-import { InternalTelemetry } from "../properties/InternalTelemetry";
+import { InternalTelemetryTable } from "../properties/InternalTelemetryTable";
export const DataSourcesSection = {
+ id: "data_sources",
name: "Data Sources",
layout: {
rows: 2,
@@ -15,20 +15,9 @@ export const DataSourcesSection = {
col: 1
},
{
- name: "Internal Telemetry",
- type: PropertyType.BasicTable,
+ ...InternalTelemetryTable,
row: 2,
- col: 1,
- layout: {
- cols: 1,
- },
- properties: [
- {
- ...InternalTelemetry,
- row: 0,
- col: 1
- }
- ]
+ col: 1
}
]
}
diff --git a/src/cti_authoring_tool/src/assets/configuration/sections/ExecutiveSummarySection.ts b/src/cti_authoring_tool/src/assets/configuration/sections/ExecutiveSummarySection.ts
index bc4a326..23cf620 100644
--- a/src/cti_authoring_tool/src/assets/configuration/sections/ExecutiveSummarySection.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/sections/ExecutiveSummarySection.ts
@@ -1,6 +1,7 @@
import { ExecutiveSummary } from "../properties/ExecutiveSummary";
export const ExecutiveSummarySection = {
+ id: "executive_summary",
name: "Executive Summary",
layout: {
rows: 4,
diff --git a/src/cti_authoring_tool/src/assets/configuration/sections/GeneralSection.ts b/src/cti_authoring_tool/src/assets/configuration/sections/GeneralSection.ts
index 071be1a..83f8091 100644
--- a/src/cti_authoring_tool/src/assets/configuration/sections/GeneralSection.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/sections/GeneralSection.ts
@@ -5,7 +5,7 @@ import { ReportNumber } from "../properties/ReportNumber";
import { TrafficLightProtocol } from "../properties/TrafficLightProtocol";
export const GeneralSection = {
- name: "General",
+ id: "general",
layout: {
rows: 2,
cols: 3
diff --git a/src/cti_authoring_tool/src/assets/configuration/sections/IndicatorAnalysisSection.ts b/src/cti_authoring_tool/src/assets/configuration/sections/IndicatorAnalysisSection.ts
index a80a59d..fb626e2 100644
--- a/src/cti_authoring_tool/src/assets/configuration/sections/IndicatorAnalysisSection.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/sections/IndicatorAnalysisSection.ts
@@ -1,6 +1,7 @@
import { IndicatorAnalysis } from "../properties/IndicatorAnalysis";
export const IndicatorAnalysisSection = {
+ id: "indicator_analysis",
name: "Indicator Analysis",
layout: {
rows: 7,
diff --git a/src/cti_authoring_tool/src/assets/configuration/sections/IntelligenceRequirementsSection.ts b/src/cti_authoring_tool/src/assets/configuration/sections/IntelligenceRequirementsSection.ts
index c887cac..2604d96 100644
--- a/src/cti_authoring_tool/src/assets/configuration/sections/IntelligenceRequirementsSection.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/sections/IntelligenceRequirementsSection.ts
@@ -1,7 +1,7 @@
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
-import { IntelligenceRequirement } from "../properties/IntelligenceRequirement";
+import { IntelligenceRequirements } from "../properties/IntelligenceRequirements";
export const IntelligenceRequirementsSection = {
+ id: "intelligence_requirements",
name: "Intelligence Requirements",
layout: {
rows: 1,
@@ -9,20 +9,9 @@ export const IntelligenceRequirementsSection = {
},
properties: [
{
- name: "Intelligence Requirements",
- type: PropertyType.BasicTable,
row: 1,
col: 1,
- layout: {
- cols: 1,
- },
- properties: [
- {
- ...IntelligenceRequirement,
- row: 0,
- col: 1
- }
- ]
+ ...IntelligenceRequirements
}
]
}
diff --git a/src/cti_authoring_tool/src/assets/configuration/sections/IntrusionAnalysisMetadataSection.ts b/src/cti_authoring_tool/src/assets/configuration/sections/IntrusionAnalysisMetadataSection.ts
index 5f40632..2c1c490 100644
--- a/src/cti_authoring_tool/src/assets/configuration/sections/IntrusionAnalysisMetadataSection.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/sections/IntrusionAnalysisMetadataSection.ts
@@ -1,9 +1,12 @@
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
+import { PropertyType } from "@/assets/scripts/PageEditor";
+import { ImportCSVPlugin } from "../plugins/ImportCSVPlugin";
import { ThreatActorMotivation } from "../properties/ThreatActorMotivation";
import { ThreatActorAttributions } from "../properties/ThreatActorAttributions";
export const IntrusionAnalysisMetadataSection = {
+ id: "metadata",
name: "Metadata",
+ path: "*.metadata",
layout: {
rows: 2,
cols: 1
@@ -15,6 +18,7 @@ export const IntrusionAnalysisMetadataSection = {
col: 1
},
{
+ id: "threat_actor_motivation",
name: "Threat Actor Motivation",
type: PropertyType.BasicTable,
row: 2,
@@ -22,6 +26,9 @@ export const IntrusionAnalysisMetadataSection = {
layout: {
cols: 1,
},
+ plugins: [
+ { module: ImportCSVPlugin }
+ ],
properties: [
{
...ThreatActorMotivation,
diff --git a/src/cti_authoring_tool/src/assets/configuration/sections/IocsSection.ts b/src/cti_authoring_tool/src/assets/configuration/sections/IocsSection.ts
index 1e91e69..b9b80d8 100644
--- a/src/cti_authoring_tool/src/assets/configuration/sections/IocsSection.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/sections/IocsSection.ts
@@ -4,6 +4,7 @@ import { IocsNetwork } from "../properties/IocsNetwork";
import { SystemArtifacts } from "../properties/SystemArtifacts";
export const IocsSection = {
+ id: "iocs",
name: "Indicators of Compromise for Hunting",
layout: {
rows: 4,
diff --git a/src/cti_authoring_tool/src/assets/configuration/sections/KeyIntelligenceGapsSection.ts b/src/cti_authoring_tool/src/assets/configuration/sections/KeyIntelligenceGapsSection.ts
index 529b4c8..d6aab77 100644
--- a/src/cti_authoring_tool/src/assets/configuration/sections/KeyIntelligenceGapsSection.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/sections/KeyIntelligenceGapsSection.ts
@@ -1,6 +1,7 @@
import { KeyIntelligenceGaps } from "../properties/KeyIntelligenceGaps";
export const KeyIntelligenceGapsSection = {
+ id: "key_intelligence_gaps",
name: "Key Intelligence Gaps",
layout: {
rows: 1,
diff --git a/src/cti_authoring_tool/src/assets/configuration/sections/KeyPointsSection.ts b/src/cti_authoring_tool/src/assets/configuration/sections/KeyPointsSection.ts
index 2d5d212..3a82804 100644
--- a/src/cti_authoring_tool/src/assets/configuration/sections/KeyPointsSection.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/sections/KeyPointsSection.ts
@@ -1,6 +1,7 @@
import { KeyPoints } from "../properties/KeyPoints";
export const KeyPointsSection = {
+ id: "key_points",
name: "Key Points",
layout: {
rows: 4,
diff --git a/src/cti_authoring_tool/src/assets/configuration/sections/MitreAttackTableIaSection.ts b/src/cti_authoring_tool/src/assets/configuration/sections/MitreAttackTableIaSection.ts
index bce0d25..ba54735 100644
--- a/src/cti_authoring_tool/src/assets/configuration/sections/MitreAttackTableIaSection.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/sections/MitreAttackTableIaSection.ts
@@ -1,8 +1,8 @@
import { MitreAttackTable } from "../properties/MitreAttackTable";
import { MitreAttackTableSimple } from "../properties/MitreAttackTableSimple";
-
export const MitreAttackTableIaSection = {
+ id: "mitre_attack",
name: "MITRE ATT&CK",
layout: {
rows: 2,
@@ -12,6 +12,7 @@ export const MitreAttackTableIaSection = {
{
...MitreAttackTable,
id: "mitre_attack_table_likely_in_network",
+ path: "*.mitre_attack_table.likely_in_network",
name: "TTPs Likely to Be in the Network",
row: 1,
col: 1
@@ -19,6 +20,7 @@ export const MitreAttackTableIaSection = {
{
...MitreAttackTableSimple,
id: "mitre_attack_table_observed",
+ path: "*.mitre_attack_table.observed",
name: "TTPs Observed in the Intrusion",
row: 2,
col: 1
diff --git a/src/cti_authoring_tool/src/assets/configuration/sections/MitreAttackTableSection.ts b/src/cti_authoring_tool/src/assets/configuration/sections/MitreAttackTableSection.ts
index 4b5093a..d432a52 100644
--- a/src/cti_authoring_tool/src/assets/configuration/sections/MitreAttackTableSection.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/sections/MitreAttackTableSection.ts
@@ -1,6 +1,7 @@
import { MitreAttackTable } from "../properties/MitreAttackTable";
export const MitreAttackTableSection = {
+ id: "mitre_attack",
name: "MITRE ATT&CK",
layout: {
rows: 1,
diff --git a/src/cti_authoring_tool/src/assets/configuration/sections/OutlookSection.ts b/src/cti_authoring_tool/src/assets/configuration/sections/OutlookSection.ts
index 5809baa..dd7c37c 100644
--- a/src/cti_authoring_tool/src/assets/configuration/sections/OutlookSection.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/sections/OutlookSection.ts
@@ -1,6 +1,7 @@
import { Outlook } from "../properties/Outlook";
export const OutlookSection = {
+ id: "outlook",
name: "Outlook",
layout: {
rows: 1,
diff --git a/src/cti_authoring_tool/src/assets/configuration/sections/SignaturesSection.ts b/src/cti_authoring_tool/src/assets/configuration/sections/SignaturesSection.ts
index b42b02f..0656fe9 100644
--- a/src/cti_authoring_tool/src/assets/configuration/sections/SignaturesSection.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/sections/SignaturesSection.ts
@@ -1,6 +1,7 @@
import { Signatures } from "../properties/Signatures";
export const SignaturesSection = {
+ id: "signatures",
name: "Signatures",
layout: {
rows: 1,
diff --git a/src/cti_authoring_tool/src/assets/configuration/sections/ThreatActorMetadataSection.ts b/src/cti_authoring_tool/src/assets/configuration/sections/ThreatActorMetadataSection.ts
index 612bcdc..500bb90 100644
--- a/src/cti_authoring_tool/src/assets/configuration/sections/ThreatActorMetadataSection.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/sections/ThreatActorMetadataSection.ts
@@ -1,13 +1,16 @@
import { Sector } from "../properties/Sector";
-import { PropertyType } from "@/assets/scripts/AppConfiguration";
+import { PropertyType } from "@/assets/scripts/PageEditor";
import { LocationRegion } from "../properties/LocationRegion";
import { Infrastructure } from "../properties/Infrastructure";
+import { ImportCSVPlugin } from "../plugins/ImportCSVPlugin";
import { ThreatActorName } from "../properties/ThreatActorName";
import { ThreatActorAliases } from "../properties/ThreatActorAliases";
import { ThreatActorMotivation } from "../properties/ThreatActorMotivation";
export const ThreatActorMetadataSection = {
+ id: "metadata",
name: "Metadata",
+ path: "*.metadata",
layout: {
rows: 5,
cols: 3
@@ -24,6 +27,7 @@ export const ThreatActorMetadataSection = {
col: [2,3]
},
{
+ id: "victim_location",
name: "Victim Location",
type: PropertyType.BasicTable,
row: 2,
@@ -31,6 +35,9 @@ export const ThreatActorMetadataSection = {
layout: {
cols: 1
},
+ plugins: [
+ { module: ImportCSVPlugin }
+ ],
properties: [
{
...LocationRegion,
@@ -40,6 +47,7 @@ export const ThreatActorMetadataSection = {
]
},
{
+ id: "sectors",
name: "Sectors",
type: PropertyType.BasicTable,
row: 3,
@@ -47,6 +55,9 @@ export const ThreatActorMetadataSection = {
layout: {
cols: 1
},
+ plugins: [
+ { module: ImportCSVPlugin }
+ ],
properties: [
{
...Sector,
@@ -56,6 +67,7 @@ export const ThreatActorMetadataSection = {
]
},
{
+ id: "infrastructure_used",
name: "Infrastructure Used",
type: PropertyType.BasicTable,
row: 4,
@@ -63,6 +75,9 @@ export const ThreatActorMetadataSection = {
layout: {
cols: 1
},
+ plugins: [
+ { module: ImportCSVPlugin }
+ ],
properties: [
{
...Infrastructure,
@@ -72,6 +87,7 @@ export const ThreatActorMetadataSection = {
]
},
{
+ id: "threat_actor_motivation",
name: "Threat Actor Motivation",
type: PropertyType.BasicTable,
row: 5,
@@ -79,6 +95,9 @@ export const ThreatActorMetadataSection = {
layout: {
cols: 1,
},
+ plugins: [
+ { module: ImportCSVPlugin }
+ ],
properties: [
{
...ThreatActorMotivation,
diff --git a/src/cti_authoring_tool/src/assets/configuration/sections/ThreatActorSummarySection.ts b/src/cti_authoring_tool/src/assets/configuration/sections/ThreatActorSummarySection.ts
index 7bb4478..eba4aad 100644
--- a/src/cti_authoring_tool/src/assets/configuration/sections/ThreatActorSummarySection.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/sections/ThreatActorSummarySection.ts
@@ -5,6 +5,7 @@ import { ThreatActorAttribution } from "../properties/ThreatActorAttribution";
import { ThreatActorInfrastructure } from "../properties/ThreatActorInfrastructure";
export const ThreatActorSummarySection = {
+ id: "threat_actor_summary",
name: "Threat Actor Summary",
layout: {
rows: 5,
diff --git a/src/cti_authoring_tool/src/assets/configuration/sections/TimelineSection.ts b/src/cti_authoring_tool/src/assets/configuration/sections/TimelineSection.ts
index e35fb3c..5f3ade9 100644
--- a/src/cti_authoring_tool/src/assets/configuration/sections/TimelineSection.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/sections/TimelineSection.ts
@@ -1,6 +1,7 @@
import { Timeline } from "../properties/Timeline";
export const TimelineSection = {
+ id: "timeline_of_activity",
name: "Timeline of Activity",
layout: {
rows: 1,
diff --git a/src/cti_authoring_tool/src/assets/configuration/sections/VictimsSection.ts b/src/cti_authoring_tool/src/assets/configuration/sections/VictimsSection.ts
index adedeca..f38ad22 100644
--- a/src/cti_authoring_tool/src/assets/configuration/sections/VictimsSection.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/sections/VictimsSection.ts
@@ -1,6 +1,7 @@
import { Victims } from "../properties/Victims";
export const VictimsSection = {
+ id: "victims",
name: "Victims",
layout: {
rows: 1,
diff --git a/src/cti_authoring_tool/src/assets/configuration/templates/Campaign.ts b/src/cti_authoring_tool/src/assets/configuration/templates/Campaign.ts
index 93f5874..cea8811 100644
--- a/src/cti_authoring_tool/src/assets/configuration/templates/Campaign.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/templates/Campaign.ts
@@ -12,8 +12,11 @@ import { KeyIntelligenceGapsSection } from "../sections/KeyIntelligenceGapsSecti
import { IntelligenceRequirementsSection } from "../sections/IntelligenceRequirementsSection";
export const Campaign: any = {
- id: "campaign_report",
+ id: "a2d30a3c-49b5-42e5-a4cb-649009fa4c9d",
name: "Campaign Report",
+ keys: [
+ "general.report_title"
+ ],
sections: [
GeneralSection,
ExecutiveSummarySection,
diff --git a/src/cti_authoring_tool/src/assets/configuration/templates/Executive.ts b/src/cti_authoring_tool/src/assets/configuration/templates/Executive.ts
index 2472e38..e715268 100644
--- a/src/cti_authoring_tool/src/assets/configuration/templates/Executive.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/templates/Executive.ts
@@ -8,8 +8,11 @@ import { KeyIntelligenceGapsSection } from "../sections/KeyIntelligenceGapsSecti
import { IntelligenceRequirementsSection } from "../sections/IntelligenceRequirementsSection";
export const Executive: any = {
- id: "executive_report",
+ id: "790fc5be-f24c-4fd7-a7e1-20a761c37812",
name: "Executive Report",
+ keys: [
+ "general.report_title"
+ ],
sections: [
GeneralSection,
ExecutiveSummarySection,
diff --git a/src/cti_authoring_tool/src/assets/configuration/templates/IntrusionAnalysis.ts b/src/cti_authoring_tool/src/assets/configuration/templates/IntrusionAnalysis.ts
index 459a935..96a44bc 100644
--- a/src/cti_authoring_tool/src/assets/configuration/templates/IntrusionAnalysis.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/templates/IntrusionAnalysis.ts
@@ -10,8 +10,11 @@ import { IntelligenceRequirementsSection } from "../sections/IntelligenceRequire
import { IntrusionAnalysisMetadataSection } from "../sections/IntrusionAnalysisMetadataSection";
export const IntrusionAnalysis: any = {
- id: "intrusion_analysis_report",
+ id: "99664720-25a7-474f-b4ea-a6db68039203",
name: "Intrusion Analysis Report",
+ keys: [
+ "general.report_title"
+ ],
sections: [
GeneralSection,
ExecutiveSummarySection,
diff --git a/src/cti_authoring_tool/src/assets/configuration/templates/ThreatActorProfile.ts b/src/cti_authoring_tool/src/assets/configuration/templates/ThreatActorProfile.ts
index 4a1a3a5..8f1c1e0 100644
--- a/src/cti_authoring_tool/src/assets/configuration/templates/ThreatActorProfile.ts
+++ b/src/cti_authoring_tool/src/assets/configuration/templates/ThreatActorProfile.ts
@@ -14,8 +14,11 @@ import { KeyIntelligenceGapsSection } from "../sections/KeyIntelligenceGapsSecti
import { IntelligenceRequirementsSection } from "../sections/IntelligenceRequirementsSection";
export const ThreatActorProfile: any = {
- id: "threat_actor_profile",
+ id: "e4e907ac-f845-4b51-a73f-ab511456ce74",
name: "Threat Actor Profile",
+ keys: [
+ "general.report_title"
+ ],
sections: [
GeneralSection,
ExecutiveSummarySection,
diff --git a/src/cti_authoring_tool/src/assets/scripts/AppConfiguration.ts b/src/cti_authoring_tool/src/assets/scripts/AppConfiguration.ts
deleted file mode 100644
index ff9bcaa..0000000
--- a/src/cti_authoring_tool/src/assets/scripts/AppConfiguration.ts
+++ /dev/null
@@ -1,321 +0,0 @@
-import { IPageSection } from "./Page/IPagesSection";
-import {
- IBasicTableProperty,
- IComplexTableProperty,
- IDateTimeProperty,
- IEnumProperty,
- INumberProperty,
- IStringProperty
-} from "./Page/Property";
-
-
-///////////////////////////////////////////////////////////////////////////////
-// 1. Property Templates ////////////////////////////////////////////////////
-///////////////////////////////////////////////////////////////////////////////
-
-
-/**
- * Property Types
- */
-export enum PropertyType {
- String, Integer, Float, Time, Date, DateTime, Enum, BasicTable, ComplexTable
-}
-
-/**
- * Alignment Types
- */
-export enum Alignment {
-
- /**
- * Top left alignment
- *
- * @example
- *
- * | X . . |
- * | . . . |
- * | . . . |
- *
- */
- TopLeft,
-
- /**
- * Top center alignment
- *
- * @example
- *
- * | . X . |
- * | . . . |
- * | . . . |
- *
- */
- TopCenter,
-
- /**
- * Top right alignment
- *
- * @example
- *
- * | . . X |
- * | . . . |
- * | . . . |
- *
- */
- TopRight,
-
- /**
- * Middle left alignment
- *
- * @example
- *
- * | . . . |
- * | X . . |
- * | . . . |
- *
- */
- MiddleLeft,
-
- /**
- * Middle center alignment
- *
- * @example
- *
- * | . . . |
- * | . X . |
- * | . . . |
- *
- */
- MiddleCenter,
-
- /**
- * Middle right alignment
- *
- * @example
- *
- * | . . . |
- * | . . X |
- * | . . . |
- *
- */
- MiddleRight,
-
- /**
- * Bottom left alignment
- *
- * @example
- *
- * | . . . |
- * | . . . |
- * | X . . |
- *
- */
- BottomLeft,
-
- /**
- * Bottom center alignment
- *
- * @example
- *
- * | . . . |
- * | . . . |
- * | . X . |
- *
- */
- BottomCenter,
-
- /**
- * Bottom right alignment
- *
- * @example
- *
- * | . . . |
- * | . . . |
- * | . . X |
- *
- */
- BottomRight
-
-}
-
-/**
- * Plugin
- */
-export interface Plugin {
- plugin: new (property: T, options?: any) => any;
- options?: () => any;
-}
-
-/**
- * Property Template
- */
-export interface PropertyTemplate {
- id?: string;
- help?: string;
- name: string;
- type: PropertyType;
- row: number | [number, number];
- col: number | [number, number];
- is_primary?: boolean;
- plugins?: Plugin[];
-}
-
-/**
- * Atomic Property Template
- */
-export interface AtomicPropertyTemplate extends PropertyTemplate {
- required?: boolean;
- alignment?: Alignment;
-}
-
-/**
- * String Property Template
- */
-export interface StringPropertyTemplate extends AtomicPropertyTemplate {
- type: PropertyType.String;
- default?: null | string;
- plugins?: Plugin[],
- suggestions?: string[];
-}
-
-/**
- * Number Property Template
- */
-export interface NumberPropertyTemplate extends AtomicPropertyTemplate {
- type: PropertyType.Integer | PropertyType.Float;
- min?: number;
- max?: number;
- default?: null | number;
- plugins?: Plugin[],
-}
-
-/**
- * Date Time Property Template
- */
-export interface DateTimePropertyTemplate extends AtomicPropertyTemplate {
- type: PropertyType.Date | PropertyType.Time | PropertyType.DateTime;
- default?: null | string | Date;
- plugins?: Plugin[],
-}
-
-/**
- * Enum Property Template
- */
-export interface EnumPropertyTemplate extends AtomicPropertyTemplate {
- type: PropertyType.Enum;
- options: { id: string, text: string, value: any }[];
- default?: null | string;
- plugins?: Plugin[],
-}
-
-/**
- * Tabular Property Template
- */
-export interface TabularPropertyTemplate extends PropertyTemplate {
- type: PropertyType.BasicTable | PropertyType.ComplexTable;
- default?: TabularPropertyRowValue[];
- layout: {
- rows?: number,
- cols: number
- }
- properties: AtomicPagePropertyTemplate[];
-}
-
-/**
- * Tabular Property Row Value
- */
-export type TabularPropertyRowValue = {
- [key: string]: null | number | string | Date
-};
-
-
-/**
- * Basic Table Property Template
- */
-export interface BasicTablePropertyTemplate extends TabularPropertyTemplate {
- type: PropertyType.BasicTable;
- layout: {
- cols: number;
- },
- plugins?: Plugin[]
-}
-
-/**
- * Complex Table Property Template
- */
-export interface ComplexTablePropertyTemplate extends TabularPropertyTemplate {
- type: PropertyType.ComplexTable;
- layout: {
- summary: string,
- rows: number,
- cols: number
- }
- plugins?: Plugin[]
-}
-
-/**
- * Atomic Page Property Template
- */
-export type AtomicPagePropertyTemplate
- = StringPropertyTemplate
- | NumberPropertyTemplate
- | DateTimePropertyTemplate
- | EnumPropertyTemplate
-
-/**
- * Page Property Template
- */
-export type PagePropertyTemplate
- = AtomicPagePropertyTemplate
- | BasicTablePropertyTemplate
- | ComplexTablePropertyTemplate
-
-
-///////////////////////////////////////////////////////////////////////////////
-// 2. Page Templates ////////////////////////////////////////////////////////
-///////////////////////////////////////////////////////////////////////////////
-
-
-/**
- * App Page Section Template
- */
-export interface PageSectionTemplate {
- id?: string;
- name: string;
- layout: {
- rows: number;
- cols: number;
- }
- properties: PagePropertyTemplate[];
- is_name_displayed?: boolean;
- is_primary?: boolean;
- plugins?: Plugin[]
-}
-
-/**
- * App Page Template
- */
-export interface PageTemplate {
- id: string,
- name: string,
- sections: PageSectionTemplate[]
-}
-
-
-///////////////////////////////////////////////////////////////////////////////
-// 3. App Configuration /////////////////////////////////////////////////////
-///////////////////////////////////////////////////////////////////////////////
-
-
-/**
- * App Configuration File
- */
-export interface AppConfiguration {
- is_web_hosted: boolean,
- file_type_name: string,
- file_type_extension: string,
- templates: PageTemplate[]
- menus: {
- help_menu: {
- help_links: { text: string, url: string }[]
- }
- }
-}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Application/AppConfiguration.ts b/src/cti_authoring_tool/src/assets/scripts/Application/AppConfiguration.ts
new file mode 100644
index 0000000..b619568
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/Application/AppConfiguration.ts
@@ -0,0 +1,13 @@
+import { PageTemplate } from "../PageEditor/PageImporter"
+
+export interface AppConfiguration {
+ is_web_hosted: boolean,
+ file_type_name: string,
+ file_type_extension: string,
+ templates: PageTemplate[]
+ menus: {
+ help_menu: {
+ help_links: { text: string, url: string }[]
+ }
+ }
+}
diff --git a/src/cti_authoring_tool/src/assets/scripts/AppSettings.ts b/src/cti_authoring_tool/src/assets/scripts/Application/AppSettings.ts
similarity index 100%
rename from src/cti_authoring_tool/src/assets/scripts/AppSettings.ts
rename to src/cti_authoring_tool/src/assets/scripts/Application/AppSettings.ts
diff --git a/src/cti_authoring_tool/src/assets/scripts/Application/Command.ts b/src/cti_authoring_tool/src/assets/scripts/Application/Command.ts
new file mode 100644
index 0000000..d58f704
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/Application/Command.ts
@@ -0,0 +1,8 @@
+import { AppCommand } from "./Commands/AppCommand";
+import { PageCommand } from "../PageEditor/Commands";
+
+export type Command
+ = AppCommand | PageCommand;
+
+export type CommandEmitter
+ = () => Promise | Command;
diff --git a/src/cti_authoring_tool/src/assets/scripts/Commands/AppCommand.ts b/src/cti_authoring_tool/src/assets/scripts/Application/Commands/AppCommand.ts
similarity index 100%
rename from src/cti_authoring_tool/src/assets/scripts/Commands/AppCommand.ts
rename to src/cti_authoring_tool/src/assets/scripts/Application/Commands/AppCommand.ts
diff --git a/src/cti_authoring_tool/src/assets/scripts/Application/Commands/ApplicationSettings/ApplicationSettings.ts b/src/cti_authoring_tool/src/assets/scripts/Application/Commands/ApplicationSettings/ApplicationSettings.ts
new file mode 100644
index 0000000..fb6a453
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/Application/Commands/ApplicationSettings/ApplicationSettings.ts
@@ -0,0 +1,17 @@
+import { ApplicationStore } from "@/store/StoreTypes";
+import { AppCommand } from "../AppCommand";
+import { LoadSettings } from "./LoadSettings";
+import { AppSettings } from "@/assets/scripts/Application/AppSettings";
+
+/**
+ * Loads the application's settings.
+ * @param context
+ * The application's context.
+ * @param settings
+ * The application's settings.
+ * @returns
+ * A command that represents the action.
+ */
+export function loadSettings(context: ApplicationStore, settings: AppSettings): AppCommand {
+ return new LoadSettings(context, settings);
+}
\ No newline at end of file
diff --git a/src/cti_authoring_tool/src/assets/scripts/Commands/AppCommands/LoadSettings.ts b/src/cti_authoring_tool/src/assets/scripts/Application/Commands/ApplicationSettings/LoadSettings.ts
similarity index 91%
rename from src/cti_authoring_tool/src/assets/scripts/Commands/AppCommands/LoadSettings.ts
rename to src/cti_authoring_tool/src/assets/scripts/Application/Commands/ApplicationSettings/LoadSettings.ts
index 8c2a15f..f533f46 100644
--- a/src/cti_authoring_tool/src/assets/scripts/Commands/AppCommands/LoadSettings.ts
+++ b/src/cti_authoring_tool/src/assets/scripts/Application/Commands/ApplicationSettings/LoadSettings.ts
@@ -1,5 +1,5 @@
import { AppCommand } from "../AppCommand";
-import { AppSettings } from "@/assets/scripts/AppSettings";
+import { AppSettings } from "@/assets/scripts/Application/AppSettings";
import { ApplicationStore } from "@/store/StoreTypes";
export class LoadSettings extends AppCommand {
diff --git a/src/cti_authoring_tool/src/assets/scripts/Application/Commands/ApplicationSettings/index.ts b/src/cti_authoring_tool/src/assets/scripts/Application/Commands/ApplicationSettings/index.ts
new file mode 100644
index 0000000..e633e2b
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/Application/Commands/ApplicationSettings/index.ts
@@ -0,0 +1 @@
+export * from "./ApplicationSettings";
\ No newline at end of file
diff --git a/src/cti_authoring_tool/src/assets/scripts/Application/Commands/FileManagement/FileManagement.ts b/src/cti_authoring_tool/src/assets/scripts/Application/Commands/FileManagement/FileManagement.ts
new file mode 100644
index 0000000..d9b2cb7
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/Application/Commands/FileManagement/FileManagement.ts
@@ -0,0 +1,111 @@
+import Configuration from "@/assets/configuration/app.config";
+import { Browser } from "@/assets/scripts/Utilities/Browser";
+import { LoadPage } from "./LoadPage";
+import { AppCommand } from "../AppCommand";
+import { UnloadPage } from "./UnloadPage";
+import { ApplicationStore } from "@/store/StoreTypes";
+import { SwitchActivePage } from "./SwitchActivePage";
+import { SavePageToDevice } from "./SavePageToDevice";
+import { PageEditor, PageTemplate } from "@/assets/scripts/PageEditor";
+
+/**
+ * Loads an empty page into the application.
+ * @param context
+ * The application's context.
+ * @param template
+ * The page's template.
+ * @returns
+ * A command that represents the action.
+ */
+export function loadNewPageFile(context: ApplicationStore, template: PageTemplate): AppCommand {
+ let page = PageEditor.createNew(template);
+ return new LoadPage(context, page);
+}
+
+/**
+ * Loads a page file export into the application.
+ * @param context
+ * The application's context.
+ * @param file
+ * The page export.
+ * @returns
+ * A command that represents the action.
+ */
+export function loadPageFromFile(context: ApplicationStore, file: string): AppCommand {
+ let contents = JSON.parse(file);
+ // Resolve Template
+ let id = contents.__document.template_identifier;
+ if(id === undefined) {
+ throw new Error("Malformed export file.")
+ }
+ let template = Configuration.templates.find(o => o.id === id);
+ if(!template) {
+ throw new Error(`Application does not support file template '${ id }'.`);
+ }
+ // Load Page
+ let page = PageEditor.fromFile(template, contents);
+ return new LoadPage(context, page);
+}
+
+/**
+ * Loads a page file from the file system, into the application.
+ * @param context
+ * The application's context.
+ * @returns
+ * A command that represents the action.
+ */
+export async function loadPageFromFileSystem(context: ApplicationStore): Promise {
+ return loadPageFromFile(context, (await Browser.openTextFileDialog()).contents as string);
+}
+
+/**
+ * Loads a page file from a remote url, into the application.
+ * @param context
+ * The application's context.
+ * @param url
+ * The remote url.
+ * @returns
+ * A command that represents the action.
+ */
+export async function loadPageFromUrl(context: ApplicationStore, url: string): Promise {
+ return loadPageFromFile(context, await (await fetch(url, { credentials: "omit" })).text());
+}
+
+/**
+ * Unloads a page out of the application.
+ * @param context
+ * The application's context.
+ * @param id
+ * The page editor's id.
+ * @returns
+ * A command that represents the action.
+ */
+export function unloadPage(context: ApplicationStore, id: string): AppCommand {
+ return new UnloadPage(context, id)
+}
+
+/**
+ * Switches the application's active page.
+ * @param context
+ * The application's context.
+ * @param id
+ * The page editor's id.
+ * @returns
+ * A command that represents the action.
+ */
+export function switchActivePage(context: ApplicationStore, id: string): AppCommand {
+ return new SwitchActivePage(context, id);
+}
+
+/**
+ * Saves a page to the user's file system.
+ * @param context
+ * The application's context.
+ * @param id
+ * The page editor's id.
+ * @returns
+ * A command that represents the action.
+ */
+export function savePageToDevice(context: ApplicationStore, id: string): AppCommand {
+ return new SavePageToDevice(context, id);
+}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Application/Commands/FileManagement/LoadPage.ts b/src/cti_authoring_tool/src/assets/scripts/Application/Commands/FileManagement/LoadPage.ts
new file mode 100644
index 0000000..f7966f5
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/Application/Commands/FileManagement/LoadPage.ts
@@ -0,0 +1,40 @@
+import { AppCommand } from "../AppCommand";
+import { PageEditor } from "@/assets/scripts/PageEditor";
+import { ApplicationStore } from "@/store/StoreTypes";
+
+export class LoadPage extends AppCommand {
+
+ /**
+ * The page editor to load.
+ */
+ private _editor: PageEditor;
+
+ /**
+ * The application context.
+ */
+ private _context: ApplicationStore;
+
+
+ /**
+ * Loads a page editor into the application.
+ * @param context
+ * The application context.
+ * @param file
+ * The page editor to load.
+ */
+ constructor(context: ApplicationStore, file: PageEditor) {
+ super();
+ this._context = context;
+ this._editor = file;
+ }
+
+
+ /**
+ * Executes the command.
+ */
+ public execute(): void {
+ this._context.editors.set(this._editor.id, this._editor);
+ this._context.activeEditor = this._editor;
+ }
+
+}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Commands/AppCommands/SavePageToDevice.ts b/src/cti_authoring_tool/src/assets/scripts/Application/Commands/FileManagement/SavePageToDevice.ts
similarity index 66%
rename from src/cti_authoring_tool/src/assets/scripts/Commands/AppCommands/SavePageToDevice.ts
rename to src/cti_authoring_tool/src/assets/scripts/Application/Commands/FileManagement/SavePageToDevice.ts
index ec1ff66..81f9a69 100644
--- a/src/cti_authoring_tool/src/assets/scripts/Commands/AppCommands/SavePageToDevice.ts
+++ b/src/cti_authoring_tool/src/assets/scripts/Application/Commands/FileManagement/SavePageToDevice.ts
@@ -1,7 +1,7 @@
import Configuration from "@/assets/configuration/app.config";
-import { Browser } from "@/assets/scripts/Browser";
-import { PageEditor } from "../../Page/PageEditor";
+import { Browser } from "@/assets/scripts/Utilities/Browser";
import { AppCommand } from "../AppCommand";
+import { PageEditor } from "@/assets/scripts/PageEditor";
import { ApplicationStore } from "@/store/StoreTypes";
export class SavePageToDevice extends AppCommand {
@@ -11,11 +11,6 @@ export class SavePageToDevice extends AppCommand {
*/
private _editor: PageEditor;
- /**
- * The application context.
- */
- private _context: ApplicationStore;
-
/**
* Saves a page to the user's file system.
@@ -26,7 +21,6 @@ export class SavePageToDevice extends AppCommand {
*/
constructor(context: ApplicationStore, id: string) {
super();
- this._context = context;
let editor = context.editors.get(id);
if(!editor) {
throw new Error(`Page '${ id }' not found.`);
@@ -40,11 +34,11 @@ export class SavePageToDevice extends AppCommand {
* Executes the command.
*/
public execute(): void {
- // Browser.downloadTextFile(
- // this._editor.page.props.toString(),
- // this._editor.toFile(),
- // Configuration.file_type_extension
- // );
+ Browser.downloadTextFile(
+ this._editor.name,
+ this._editor.toFile(),
+ Configuration.file_type_extension
+ );
}
}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Commands/AppCommands/SwitchActiveFile.ts b/src/cti_authoring_tool/src/assets/scripts/Application/Commands/FileManagement/SwitchActivePage.ts
similarity index 80%
rename from src/cti_authoring_tool/src/assets/scripts/Commands/AppCommands/SwitchActiveFile.ts
rename to src/cti_authoring_tool/src/assets/scripts/Application/Commands/FileManagement/SwitchActivePage.ts
index 0f9a986..63f015a 100644
--- a/src/cti_authoring_tool/src/assets/scripts/Commands/AppCommands/SwitchActiveFile.ts
+++ b/src/cti_authoring_tool/src/assets/scripts/Application/Commands/FileManagement/SwitchActivePage.ts
@@ -1,8 +1,8 @@
import { AppCommand } from "../AppCommand";
-import { PageEditor } from "../../Page/PageEditor";
+import { PageEditor } from "@/assets/scripts/PageEditor";
import { ApplicationStore } from "@/store/StoreTypes";
-export class SwitchActiveFile extends AppCommand {
+export class SwitchActivePage extends AppCommand {
/**
* The page editor to load.
@@ -16,11 +16,11 @@ export class SwitchActiveFile extends AppCommand {
/**
- * Switches the application's active page.
+ * Switches the application's active page editor.
* @param context
* The application context.
* @param id
- * The id of the page editor to switch to.
+ * The page editor's id.
*/
constructor(context: ApplicationStore, id: string) {
super();
diff --git a/src/cti_authoring_tool/src/assets/scripts/Commands/AppCommands/UnloadFile.ts b/src/cti_authoring_tool/src/assets/scripts/Application/Commands/FileManagement/UnloadPage.ts
similarity index 87%
rename from src/cti_authoring_tool/src/assets/scripts/Commands/AppCommands/UnloadFile.ts
rename to src/cti_authoring_tool/src/assets/scripts/Application/Commands/FileManagement/UnloadPage.ts
index 438637b..fdaaf90 100644
--- a/src/cti_authoring_tool/src/assets/scripts/Commands/AppCommands/UnloadFile.ts
+++ b/src/cti_authoring_tool/src/assets/scripts/Application/Commands/FileManagement/UnloadPage.ts
@@ -1,8 +1,8 @@
import { AppCommand } from "../AppCommand";
-import { PageEditor } from "../../Page/PageEditor";
+import { PageEditor } from "@/assets/scripts/PageEditor";
import { ApplicationStore } from "@/store/StoreTypes";
-export class UnloadFile extends AppCommand {
+export class UnloadPage extends AppCommand {
/**
* The page editor to unload.
@@ -16,11 +16,11 @@ export class UnloadFile extends AppCommand {
/**
- * Unloads a page editor from the application.
+ * Unloads a page editor out of the application.
* @param context
* The application context.
* @param file
- * The id of the page editor to unload.
+ * The page editor's id.
*/
constructor(context: ApplicationStore, id: string) {
super();
diff --git a/src/cti_authoring_tool/src/assets/scripts/Application/Commands/FileManagement/index.ts b/src/cti_authoring_tool/src/assets/scripts/Application/Commands/FileManagement/index.ts
new file mode 100644
index 0000000..1f54c2a
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/Application/Commands/FileManagement/index.ts
@@ -0,0 +1 @@
+export * from "./FileManagement";
\ No newline at end of file
diff --git a/src/cti_authoring_tool/src/assets/scripts/Application/Commands/PageElement/PageElement.ts b/src/cti_authoring_tool/src/assets/scripts/Application/Commands/PageElement/PageElement.ts
new file mode 100644
index 0000000..88645d0
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/Application/Commands/PageElement/PageElement.ts
@@ -0,0 +1,30 @@
+import { AppCommand } from "../AppCommand";
+import { UndoPageCommand } from "./UndoPageCommand";
+import { RedoPageCommand } from "./RedoPageCommand";
+import { ApplicationStore } from "@/store/StoreTypes";
+
+/**
+ * Undoes the last page command.
+ * @param context
+ * The application's context.
+ * @param id
+ * The page editor's id.
+ * @returns
+ * A command that represents the action.
+ */
+export function undoPageCommand(context: ApplicationStore, id: string): AppCommand {
+ return new UndoPageCommand(context, id);
+}
+
+/**
+ * Redoes the last undone page command.
+ * @param context
+ * The application's context.
+ * @param id
+ * The page editor's id.
+ * @returns
+ * A command that represents the action.
+ */
+export function redoPageCommand(context: ApplicationStore, id: string): AppCommand {
+ return new RedoPageCommand(context, id);
+}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Commands/AppCommands/RedoPageCommand.ts b/src/cti_authoring_tool/src/assets/scripts/Application/Commands/PageElement/RedoPageCommand.ts
similarity index 93%
rename from src/cti_authoring_tool/src/assets/scripts/Commands/AppCommands/RedoPageCommand.ts
rename to src/cti_authoring_tool/src/assets/scripts/Application/Commands/PageElement/RedoPageCommand.ts
index c6b6896..b17cbf5 100644
--- a/src/cti_authoring_tool/src/assets/scripts/Commands/AppCommands/RedoPageCommand.ts
+++ b/src/cti_authoring_tool/src/assets/scripts/Application/Commands/PageElement/RedoPageCommand.ts
@@ -1,5 +1,5 @@
import { AppCommand } from "../AppCommand";
-import { PageEditor } from "../../Page/PageEditor";
+import { PageEditor } from "@/assets/scripts/PageEditor";
import { ApplicationStore } from "@/store/StoreTypes";
export class RedoPageCommand extends AppCommand {
diff --git a/src/cti_authoring_tool/src/assets/scripts/Commands/AppCommands/UndoPageCommand.ts b/src/cti_authoring_tool/src/assets/scripts/Application/Commands/PageElement/UndoPageCommand.ts
similarity index 93%
rename from src/cti_authoring_tool/src/assets/scripts/Commands/AppCommands/UndoPageCommand.ts
rename to src/cti_authoring_tool/src/assets/scripts/Application/Commands/PageElement/UndoPageCommand.ts
index b2d9a32..0997064 100644
--- a/src/cti_authoring_tool/src/assets/scripts/Commands/AppCommands/UndoPageCommand.ts
+++ b/src/cti_authoring_tool/src/assets/scripts/Application/Commands/PageElement/UndoPageCommand.ts
@@ -1,5 +1,5 @@
import { AppCommand } from "../AppCommand";
-import { PageEditor } from "../../Page/PageEditor";
+import { PageEditor } from "@/assets/scripts/PageEditor";
import { ApplicationStore } from "@/store/StoreTypes";
export class UndoPageCommand extends AppCommand {
diff --git a/src/cti_authoring_tool/src/assets/scripts/Application/Commands/PageElement/index.ts b/src/cti_authoring_tool/src/assets/scripts/Application/Commands/PageElement/index.ts
new file mode 100644
index 0000000..c1409d9
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/Application/Commands/PageElement/index.ts
@@ -0,0 +1 @@
+export * from "./PageElement";
diff --git a/src/cti_authoring_tool/src/assets/scripts/Commands/AppCommands/DeselectProperty.ts b/src/cti_authoring_tool/src/assets/scripts/Application/Commands/PropertyElement/DeselectAtomicProperty.ts
similarity index 65%
rename from src/cti_authoring_tool/src/assets/scripts/Commands/AppCommands/DeselectProperty.ts
rename to src/cti_authoring_tool/src/assets/scripts/Application/Commands/PropertyElement/DeselectAtomicProperty.ts
index a25951f..7e785b7 100644
--- a/src/cti_authoring_tool/src/assets/scripts/Commands/AppCommands/DeselectProperty.ts
+++ b/src/cti_authoring_tool/src/assets/scripts/Application/Commands/PropertyElement/DeselectAtomicProperty.ts
@@ -1,7 +1,7 @@
import { AppCommand } from "../AppCommand";
-import { AtomicProperty } from "../../Page/Property/AtomicProperty/AtomicProperty";
+import { AtomicProperty } from "@/assets/scripts/Page";
-export class DeselectProperty extends AppCommand {
+export class DeselectAtomicProperty extends AppCommand {
/**
* The property to deselect.
@@ -10,7 +10,7 @@ export class DeselectProperty extends AppCommand {
/**
- * Deselects a property from the DOM.
+ * Deselects an atomic property from the DOM.
* @param property
* The property to deselect.
*/
@@ -24,7 +24,7 @@ export class DeselectProperty extends AppCommand {
* Executes the command.
*/
public execute(): void {
- this._property.onDeselect();
+ this._property.emit("select");
}
}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Commands/AppCommands/DestroyProperty.ts b/src/cti_authoring_tool/src/assets/scripts/Application/Commands/PropertyElement/DestroyProperty.ts
similarity index 83%
rename from src/cti_authoring_tool/src/assets/scripts/Commands/AppCommands/DestroyProperty.ts
rename to src/cti_authoring_tool/src/assets/scripts/Application/Commands/PropertyElement/DestroyProperty.ts
index da57709..17dbf43 100644
--- a/src/cti_authoring_tool/src/assets/scripts/Commands/AppCommands/DestroyProperty.ts
+++ b/src/cti_authoring_tool/src/assets/scripts/Application/Commands/PropertyElement/DestroyProperty.ts
@@ -1,5 +1,5 @@
+import { Property } from "@/assets/scripts/Page";
import { AppCommand } from "../AppCommand";
-import { Property } from "../../Page/Property/Property";
export class DestroyProperty extends AppCommand {
@@ -24,7 +24,7 @@ export class DestroyProperty extends AppCommand {
* Executes the command.
*/
public execute(): void {
- this._property.onDestroy();
+ this._property.emit("destroy");
}
}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Application/Commands/PropertyElement/InvokePropertyAction.ts b/src/cti_authoring_tool/src/assets/scripts/Application/Commands/PropertyElement/InvokePropertyAction.ts
new file mode 100644
index 0000000..2ad8061
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/Application/Commands/PropertyElement/InvokePropertyAction.ts
@@ -0,0 +1,39 @@
+
+import { Property } from "@/assets/scripts/Page";
+import { AppCommand } from "../AppCommand";
+
+export class InvokePropertyAction extends AppCommand {
+
+ /**
+ * The action's id.
+ */
+ private _id: string;
+
+ /**
+ * The property.
+ */
+ private _property: Property;
+
+
+ /**
+ * Invokes a property's action.
+ * @param property
+ * The property.
+ * @param id
+ * The action's id.
+ */
+ constructor(property: Property, id: string) {
+ super();
+ this._property = property;
+ this._id = id;
+ }
+
+
+ /**
+ * Executes the command.
+ */
+ public execute(): void {
+ this._property.invokeAction(this._id);
+ }
+
+}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Commands/AppCommands/MountProperty.ts b/src/cti_authoring_tool/src/assets/scripts/Application/Commands/PropertyElement/MountProperty.ts
similarity index 86%
rename from src/cti_authoring_tool/src/assets/scripts/Commands/AppCommands/MountProperty.ts
rename to src/cti_authoring_tool/src/assets/scripts/Application/Commands/PropertyElement/MountProperty.ts
index 85fbea6..70ab6c0 100644
--- a/src/cti_authoring_tool/src/assets/scripts/Commands/AppCommands/MountProperty.ts
+++ b/src/cti_authoring_tool/src/assets/scripts/Application/Commands/PropertyElement/MountProperty.ts
@@ -1,4 +1,5 @@
-import { Property } from "../../Page/Property/Property";
+
+import { Property } from "@/assets/scripts/Page";
import { AppCommand } from "../AppCommand";
export class MountProperty extends AppCommand {
@@ -32,7 +33,7 @@ export class MountProperty extends AppCommand {
* Executes the command.
*/
public execute(): void {
- this._property.onMount(this._el);
+ this._property.emit("mount", this._el);
}
}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Application/Commands/PropertyElement/PropertyElement.ts b/src/cti_authoring_tool/src/assets/scripts/Application/Commands/PropertyElement/PropertyElement.ts
new file mode 100644
index 0000000..451f651
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/Application/Commands/PropertyElement/PropertyElement.ts
@@ -0,0 +1,66 @@
+import { AppCommand } from "../AppCommand";
+import { MountProperty } from "./MountProperty";
+import { DestroyProperty } from "./DestroyProperty";
+import { InvokePropertyAction } from "./InvokePropertyAction";
+import { SelectAtomicProperty } from "./SelectAtomicProperty";
+import { DeselectAtomicProperty } from "./DeselectAtomicProperty";
+import { AtomicProperty, Property } from "@/assets/scripts/Page";
+
+/**
+ * Mounts a property to the DOM.
+ * @param prop
+ * The property.
+ * @param el
+ * The property's HTML container.
+ * @returns
+ * A command that represents the action.
+ */
+export function mountProperty(prop: Property, el: HTMLElement): AppCommand {
+ return new MountProperty(prop, el);
+}
+
+/**
+ * Removes a property from the DOM.
+ * @param prop
+ * The property.
+ * @returns
+ * A command that represents the action.
+ */
+export function destroyProperty(prop: Property) {
+ return new DestroyProperty(prop);
+}
+
+/**
+ * Invokes a property's action.
+ * @param prop
+ * The property.
+ * @param id
+ * The action's id.
+ * @returns
+ * A command that represents the action.
+ */
+export function invokePropertyAction(prop: Property, id: string): AppCommand {
+ return new InvokePropertyAction(prop, id);
+}
+
+/**
+ * Selects an atomic property from the DOM.
+ * @param prop
+ * The atomic property.
+ * @returns
+ * A command that represents the action.
+ */
+export function selectAtomicProperty(prop: AtomicProperty): AppCommand {
+ return new SelectAtomicProperty(prop);
+}
+
+/**
+ * Deselects an atomic property from the DOM.
+ * @param prop
+ * The atomic property.
+ * @returns
+ * A command that represents the action.
+ */
+export function deselectAtomicProperty(prop: AtomicProperty): AppCommand {
+ return new DeselectAtomicProperty(prop);
+}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Commands/AppCommands/SelectProperty.ts b/src/cti_authoring_tool/src/assets/scripts/Application/Commands/PropertyElement/SelectAtomicProperty.ts
similarity index 65%
rename from src/cti_authoring_tool/src/assets/scripts/Commands/AppCommands/SelectProperty.ts
rename to src/cti_authoring_tool/src/assets/scripts/Application/Commands/PropertyElement/SelectAtomicProperty.ts
index 430ecdb..e42e400 100644
--- a/src/cti_authoring_tool/src/assets/scripts/Commands/AppCommands/SelectProperty.ts
+++ b/src/cti_authoring_tool/src/assets/scripts/Application/Commands/PropertyElement/SelectAtomicProperty.ts
@@ -1,7 +1,7 @@
import { AppCommand } from "../AppCommand";
-import { AtomicProperty } from "../../Page/Property/AtomicProperty/AtomicProperty";
+import { AtomicProperty } from "@/assets/scripts/Page";
-export class SelectProperty extends AppCommand {
+export class SelectAtomicProperty extends AppCommand {
/**
* The property to select.
@@ -10,7 +10,7 @@ export class SelectProperty extends AppCommand {
/**
- * Selects a property from the DOM.
+ * Selects an atomic property from the DOM.
* @param property
* The property to select.
*/
@@ -24,7 +24,7 @@ export class SelectProperty extends AppCommand {
* Executes the command.
*/
public execute(): void {
- this._property.onSelect();
+ this._property.emit("select");
}
}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Application/Commands/PropertyElement/index.ts b/src/cti_authoring_tool/src/assets/scripts/Application/Commands/PropertyElement/index.ts
new file mode 100644
index 0000000..741efea
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/Application/Commands/PropertyElement/index.ts
@@ -0,0 +1 @@
+export * from "./PropertyElement";
\ No newline at end of file
diff --git a/src/cti_authoring_tool/src/assets/scripts/Commands/AppCommands/DestroyPageSection.ts b/src/cti_authoring_tool/src/assets/scripts/Application/Commands/SectionElement/DestroySection.ts
similarity index 61%
rename from src/cti_authoring_tool/src/assets/scripts/Commands/AppCommands/DestroyPageSection.ts
rename to src/cti_authoring_tool/src/assets/scripts/Application/Commands/SectionElement/DestroySection.ts
index 99ab16a..077fa7a 100644
--- a/src/cti_authoring_tool/src/assets/scripts/Commands/AppCommands/DestroyPageSection.ts
+++ b/src/cti_authoring_tool/src/assets/scripts/Application/Commands/SectionElement/DestroySection.ts
@@ -1,12 +1,12 @@
+import { Section } from "@/assets/scripts/Page";
import { AppCommand } from "../AppCommand";
-import { PageSection } from "../../Page/PageSection";
-export class DestroyPageSection extends AppCommand {
+export class DestroySection extends AppCommand {
/**
* The section to destroy.
*/
- private _section: PageSection;
+ private _section: Section;
/**
@@ -14,7 +14,7 @@ export class DestroyPageSection extends AppCommand {
* @param section
* The section to destroy.
*/
- constructor(section: PageSection) {
+ constructor(section: Section) {
super();
this._section = section;
}
@@ -24,7 +24,7 @@ export class DestroyPageSection extends AppCommand {
* Executes the command.
*/
public execute(): void {
- this._section.onDestroy();
+ this._section.emit("destroy");
}
}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Commands/AppCommands/MountPageSection.ts b/src/cti_authoring_tool/src/assets/scripts/Application/Commands/SectionElement/MountSection.ts
similarity index 67%
rename from src/cti_authoring_tool/src/assets/scripts/Commands/AppCommands/MountPageSection.ts
rename to src/cti_authoring_tool/src/assets/scripts/Application/Commands/SectionElement/MountSection.ts
index 0b6c112..aacfb0e 100644
--- a/src/cti_authoring_tool/src/assets/scripts/Commands/AppCommands/MountPageSection.ts
+++ b/src/cti_authoring_tool/src/assets/scripts/Application/Commands/SectionElement/MountSection.ts
@@ -1,12 +1,12 @@
+import { Section } from "@/assets/scripts/Page";
import { AppCommand } from "../AppCommand";
-import { PageSection } from "../../Page/PageSection";
-export class MountPageSection extends AppCommand {
+export class MountSection extends AppCommand {
/**
* The section to mount.
*/
- private _section: PageSection;
+ private _section: Section;
/**
* The section's HTML container.
@@ -21,7 +21,7 @@ export class MountPageSection extends AppCommand {
* @param el
* The section's HTML container.
*/
- constructor(section: PageSection, el: HTMLElement) {
+ constructor(section: Section, el: HTMLElement) {
super();
this._section = section;
this._el = el;
@@ -32,7 +32,7 @@ export class MountPageSection extends AppCommand {
* Executes the command.
*/
public execute(): void {
- this._section.onMount(this._el);
+ this._section.emit("mount", this._el);
}
}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Application/Commands/SectionElement/SectionElement.ts b/src/cti_authoring_tool/src/assets/scripts/Application/Commands/SectionElement/SectionElement.ts
new file mode 100644
index 0000000..e1433e6
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/Application/Commands/SectionElement/SectionElement.ts
@@ -0,0 +1,28 @@
+import { Section } from "@/assets/scripts/Page";
+import { AppCommand } from "../AppCommand";
+import { MountSection } from "./MountSection";
+import { DestroySection } from "./DestroySection";
+
+/**
+ * Mounts a page section to the DOM.
+ * @param section
+ * The page section.
+ * @param el
+ * The section's HTML container.
+ * @returns
+ * A command that represents the action.
+ */
+export function mountSection(section: Section, el: HTMLElement): AppCommand {
+ return new MountSection(section, el);
+}
+
+/**
+ * Removes a page section from the DOM.
+ * @param section
+ * The page section.
+ * @returns
+ * A command that represents the action.
+ */
+export function destroySection(section: Section) {
+ return new DestroySection(section);
+}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Application/Commands/SectionElement/index.ts b/src/cti_authoring_tool/src/assets/scripts/Application/Commands/SectionElement/index.ts
new file mode 100644
index 0000000..5eff4d2
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/Application/Commands/SectionElement/index.ts
@@ -0,0 +1 @@
+export * from "./SectionElement";
\ No newline at end of file
diff --git a/src/cti_authoring_tool/src/assets/scripts/Commands/AppCommands/OpenHyperlink.ts b/src/cti_authoring_tool/src/assets/scripts/Application/Commands/ViewManagement/OpenHyperlink.ts
similarity index 90%
rename from src/cti_authoring_tool/src/assets/scripts/Commands/AppCommands/OpenHyperlink.ts
rename to src/cti_authoring_tool/src/assets/scripts/Application/Commands/ViewManagement/OpenHyperlink.ts
index 6d2b1c5..ec6717b 100644
--- a/src/cti_authoring_tool/src/assets/scripts/Commands/AppCommands/OpenHyperlink.ts
+++ b/src/cti_authoring_tool/src/assets/scripts/Application/Commands/ViewManagement/OpenHyperlink.ts
@@ -11,8 +11,6 @@ export class OpenHyperlink extends AppCommand {
/**
* Opens an external hyperlink.
- * @param context
- * The application context.
* @param url
* The hyperlink's url.
*/
diff --git a/src/cti_authoring_tool/src/assets/scripts/Commands/AppCommands/SwitchToFullscreen.ts b/src/cti_authoring_tool/src/assets/scripts/Application/Commands/ViewManagement/SwitchToFullscreen.ts
similarity index 100%
rename from src/cti_authoring_tool/src/assets/scripts/Commands/AppCommands/SwitchToFullscreen.ts
rename to src/cti_authoring_tool/src/assets/scripts/Application/Commands/ViewManagement/SwitchToFullscreen.ts
diff --git a/src/cti_authoring_tool/src/assets/scripts/Application/Commands/ViewManagement/ViewManagement.ts b/src/cti_authoring_tool/src/assets/scripts/Application/Commands/ViewManagement/ViewManagement.ts
new file mode 100644
index 0000000..a5f1cc3
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/Application/Commands/ViewManagement/ViewManagement.ts
@@ -0,0 +1,23 @@
+import { AppCommand } from "../AppCommand";
+import { OpenHyperlink } from "./OpenHyperlink"
+import { SwitchToFullscreen } from "./SwitchToFullscreen";
+
+/**
+ * Opens an external hyperlink.
+ * @param url
+ * The hyperlink's url.
+ * @returns
+ * A command that represents the action.
+ */
+export function openHyperlink(url: string): AppCommand {
+ return new OpenHyperlink(url);
+}
+
+/**
+ * Switches the application to fullscreen mode.
+ * @returns
+ * A command that represents the action.
+ */
+export function switchToFullscreen(): AppCommand {
+ return new SwitchToFullscreen();
+}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Application/Commands/ViewManagement/index.ts b/src/cti_authoring_tool/src/assets/scripts/Application/Commands/ViewManagement/index.ts
new file mode 100644
index 0000000..eeb6d13
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/Application/Commands/ViewManagement/index.ts
@@ -0,0 +1 @@
+export * from "./ViewManagement";
\ No newline at end of file
diff --git a/src/cti_authoring_tool/src/assets/scripts/Application/Commands/index.ts b/src/cti_authoring_tool/src/assets/scripts/Application/Commands/index.ts
new file mode 100644
index 0000000..4c3faba
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/Application/Commands/index.ts
@@ -0,0 +1,7 @@
+export * from "./ApplicationSettings";
+export * from "./FileManagement";
+export * from "./PageElement";
+export * from "./PropertyElement";
+export * from "./SectionElement";
+export * from "./ViewManagement";
+export * from "./AppCommand";
\ No newline at end of file
diff --git a/src/cti_authoring_tool/src/assets/scripts/ContextMenuTypes.ts b/src/cti_authoring_tool/src/assets/scripts/Application/ContextMenuTypes.ts
similarity index 100%
rename from src/cti_authoring_tool/src/assets/scripts/ContextMenuTypes.ts
rename to src/cti_authoring_tool/src/assets/scripts/Application/ContextMenuTypes.ts
diff --git a/src/cti_authoring_tool/src/assets/scripts/Commands/AppCommands/LoadFile.ts b/src/cti_authoring_tool/src/assets/scripts/Commands/AppCommands/LoadFile.ts
deleted file mode 100644
index e2bf0fc..0000000
--- a/src/cti_authoring_tool/src/assets/scripts/Commands/AppCommands/LoadFile.ts
+++ /dev/null
@@ -1,101 +0,0 @@
-import { Browser } from "../../Browser";
-import { AppCommand } from "../AppCommand";
-import { PageEditor } from "../../Page/PageEditor";
-import { PageTemplate } from "../../AppConfiguration";
-import { ApplicationStore } from "@/store/StoreTypes";
-
-export class LoadFile extends AppCommand {
-
- /**
- * The page editor to load.
- */
- private _editor: PageEditor;
-
- /**
- * The application context.
- */
- private _context: ApplicationStore;
-
-
- /**
- * Loads a page editor into the application.
- * @param context
- * The application context.
- * @param file
- * The page editor to load.
- */
- constructor(context: ApplicationStore, file: PageEditor) {
- super();
- this._context = context;
- this._editor = file;
- }
-
-
- /**
- * Loads an empty page file into the application.
- * @param context
- * The application context.
- * @param template
- * The page's template.
- * @returns
- * The {@link LoadFile} command.
- */
- public static async fromNew(context: ApplicationStore, template: PageTemplate): Promise {
- let page = PageEditor.createNew(template);
- return new LoadFile(context, page);
- }
-
- /**
- * Loads a page export into the application.
- * @param context
- * The application context.
- * @param file
- * The page export.
- * @returns
- * The {@link LoadFile} command.
- */
- public static async fromFile(context: ApplicationStore, file: string): Promise {
- // TODO: Resolve template
- let page = PageEditor.fromFile({ id: "", name: "", sections: [] }, file);
- return new LoadFile(context, page);
- }
-
- /**
- * Loads a page file from the file system, into the application.
- * @param context
- * The application context.
- * @returns
- * The {@link LoadFile} command.
- */
- public static async fromFileSystem(context: ApplicationStore): Promise {
- // TODO: Resolve template
- let file = (await Browser.openTextFileDialog()).contents as string;
- let page = PageEditor.fromFile({ id: "", name: "", sections: [] }, file);
- return new LoadFile(context, page);
- }
-
- /**
- * Loads a page file from a remote url, into the application.
- * @param context
- * The application context.
- * @param url
- * The remote url.
- * @returns
- * The {@link LoadFile} command.
- */
- public static async fromUrl(context: ApplicationStore, url: string): Promise {
- // TODO: Resolve template
- let file = await (await fetch(url, { credentials: "omit" })).text();
- let page = PageEditor.fromFile({ id: "", name: "", sections: [] }, file);
- return new LoadFile(context, page);
- }
-
- /**
- * Executes the command.
- */
- public execute(): void {
- this._context.editors.set(this._editor.id, this._editor);
- this._context.activeEditor = this._editor;
- }
-
-}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Commands/AppCommands/index.ts b/src/cti_authoring_tool/src/assets/scripts/Commands/AppCommands/index.ts
deleted file mode 100644
index 40916bc..0000000
--- a/src/cti_authoring_tool/src/assets/scripts/Commands/AppCommands/index.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-export * from "./DeselectProperty";
-export * from "./DestroyPageSection";
-export * from "./DestroyProperty";
-export * from "./LoadFile";
-export * from "./LoadSettings";
-export * from "./MountPageSection";
-export * from "./MountProperty";
-export * from "./OpenHyperlink";
-export * from "./RedoPageCommand";
-export * from "./SavePageToDevice";
-export * from "./SelectProperty";
-export * from "./SwitchActiveFile";
-export * from "./SwitchToFullscreen";
-export * from "./UndoPageCommand";
-export * from "./UnloadFile";
\ No newline at end of file
diff --git a/src/cti_authoring_tool/src/assets/scripts/Commands/Command.ts b/src/cti_authoring_tool/src/assets/scripts/Commands/Command.ts
deleted file mode 100644
index 7e65f4f..0000000
--- a/src/cti_authoring_tool/src/assets/scripts/Commands/Command.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import { AppCommand } from "./AppCommand";
-import { PageCommand } from "./PageCommand";
-
-export type Command
- = AppCommand | PageCommand;
-
-export type CommandEmitter
- = () => Promise | Command
\ No newline at end of file
diff --git a/src/cti_authoring_tool/src/assets/scripts/Commands/PageCommands/index.ts b/src/cti_authoring_tool/src/assets/scripts/Commands/PageCommands/index.ts
deleted file mode 100644
index 1a59f74..0000000
--- a/src/cti_authoring_tool/src/assets/scripts/Commands/PageCommands/index.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-/**
- * TODO:
- * Create a static class for each property type. Provide static methods that do
- * things like StringProperty.set(), StringProperty.clear(),
- * ComplexTableProperty.collapse(), ComplexTableProperty.uncollapse() to
- * generate PageCommands.
- *
- * This idea should be unified with the newCommand() construct somehow.
- */
-
-export * from "./ComplexTablePropertySetRowCollapse";
-export * from "./DateTimePropertySet";
-export * from "./EnumPropertySet";
-export * from "./NumberPropertySet";
-export * from "./StringPropertySet";
-export * from "./TabularPropertyCreateRow";
-export * from "./TabularPropertyDeleteRow";
-export * from "./TabularPropertyMoveRow";
-export * from "./TabularPropertyReorder";
diff --git a/src/cti_authoring_tool/src/assets/scripts/Page/Events/EventEmitter.ts b/src/cti_authoring_tool/src/assets/scripts/Page/Events/EventEmitter.ts
new file mode 100644
index 0000000..9bca19f
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/Page/Events/EventEmitter.ts
@@ -0,0 +1,80 @@
+export class EventEmitter {
+
+ /**
+ * The event emitter's index of event listeners.
+ */
+ private _listeners: Map;
+
+
+ /**
+ * Creates a new {@link EventEmitter}.
+ */
+ constructor(){
+ this._listeners = new Map();
+ }
+
+
+ /**
+ * Dispatches the event listeners associated with a given event.
+ * @param event
+ * The name of the event to raise.
+ * @param args
+ * The arguments to pass to the event listeners.
+ */
+ public emit(event: string, ...args: any[]) {
+ if(this._listeners.has(event)) {
+ let listeners = this._listeners.get(event)!;
+ for(let i = listeners.length - 1; 0 <= i; i--) {
+ listeners[i](...args);
+ }
+ }
+ }
+
+ /**
+ * Adds an event listener to an event.
+ * @param event
+ * The name of the event.
+ * @param callback
+ * The function to call when the event is raised.
+ */
+ public on(event: string, callback: Function) {
+ if(!this._listeners.has(event)) {
+ this._listeners.set(event, []);
+ }
+ this._listeners.get(event)!.unshift(callback);
+ }
+
+ /**
+ * Adds a one-time event listener to an event.
+ * @param event
+ * The name of the event.
+ * @param callback
+ * The function to call when the event is raised.
+ */
+ public once(event: string, callback: Function) {
+ if(!this._listeners.has(event)) {
+ this._listeners.set(event, []);
+ }
+ let once = (...args: any[]) => {
+ let listeners = this._listeners.get(event)!;
+ listeners.splice(listeners.indexOf(once), 1);
+ callback(...args);
+ }
+ this._listeners.get(event)!.unshift(once);
+ }
+
+ /**
+ * Removes an event listener from an event.
+ * @param event
+ * The name of the event.
+ * @param callback
+ * The function to remove.
+ */
+ public off(event: string, callback: Function) {
+ if(this._listeners.has(event)) {
+ let listeners = this._listeners.get(event)!;
+ listeners.splice(listeners.indexOf(callback), 1);
+ }
+ }
+
+}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Page/IPagesSection.ts b/src/cti_authoring_tool/src/assets/scripts/Page/IPagesSection.ts
deleted file mode 100644
index 54496bc..0000000
--- a/src/cti_authoring_tool/src/assets/scripts/Page/IPagesSection.ts
+++ /dev/null
@@ -1,98 +0,0 @@
-import { IProperty } from "./Property/IProperty";
-
-export interface IPageSection {
-
- /**
- * The section's id.
- */
- readonly id: string;
-
- /**
- * The section's name.
- */
- readonly name: string;
-
- /**
- * The section's layout.
- */
- readonly layout: {
-
- /**
- * The number of rows in the section.
- */
- rows: number,
-
- /**
- * The number of columns in the section.
- */
- cols: number
-
- };
-
- /**
- * The section's properties.
- */
- readonly properties: Map;
-
- /**
- * True if the section's name should be displayed, false otherwise.
- */
- readonly isNameDisplayed: boolean;
-
- /**
- * The section's primary status.
- */
- readonly isPrimary: boolean;
-
-
-
- /**
- * Adds an event listener to the property.
- * @param event
- * The event to subscribe to.
- * @param callback
- * The function to call once the event has fired.
- */
- on(event: K, callback: PropertyEvents[K]): void;
-
- /**
- * Adds an event listener to the property that will be fired once and then
- * removed.
- * @param event
- * The event to subscribe to.
- * @param callback
- * The function to call once the event has fired.
- */
- once(event: K, callback: PropertyEvents[K]): void;
-
- /**
- * Removes all event listeners associated with a given event. If no event
- * name is specified, all event listeners are removed.
- * @param event
- * The name of the event.
- */
- removeAllListeners(event?: K): void;
-
- /**
- * Returns a string representation of the property.
- * @returns
- * A string representation of the property.
- */
- toString(): string | undefined;
-
-}
-
-
-///////////////////////////////////////////////////////////////////////////////
-// Internal Types ///////////////////////////////////////////////////////////
-///////////////////////////////////////////////////////////////////////////////
-
-
-// Event types
-export interface PropertyEvents {
- "mount" : (el: HTMLElement) => void,
- "destroy" : () => void,
- "property-select" : (property: IProperty) => void,
- "property-deselect" : (property: IProperty) => void,
- "property-update" : (property: IProperty, newValue: any, oldValue: any) => void
-}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Page/Page.ts b/src/cti_authoring_tool/src/assets/scripts/Page/Page.ts
index 14ebd39..061f750 100644
--- a/src/cti_authoring_tool/src/assets/scripts/Page/Page.ts
+++ b/src/cti_authoring_tool/src/assets/scripts/Page/Page.ts
@@ -1,73 +1,174 @@
-import { Crypto } from "../Utilities/Crypto";
-import { PageSection } from "./PageSection";
-import { PageTemplate } from "../AppConfiguration";
+import { PageElement } from "./PageElement";
+import { PageAssembler } from "./PageAssembler";
+import { PageParameters } from "./PageParameters";
+import { Plugin, PluginManager } from "./Plugins";
+import { Section, SectionAssembler } from "./Section";
-export class Page {
+export class Page extends PageElement {
/**
- * The page's instance id.
+ * The page's id.
*/
- public instance: string;
+ public readonly id: string;
/**
- * The page template's id.
+ * The page's export path.
*/
- public id: string;
+ public readonly path: string;
/**
- * The page template's name.
+ * The page's sections.
*/
- public template: string;
+ public readonly sections: ReadonlyMap;
/**
- * The page's sections.
+ * The section's plugins.
*/
- public sections: Map;
+ private _plugins: PluginManager | null;
+
+ /**
+ * Creates a new {@link Page}.
+ * @param params
+ * The page's parameters.
+ */
+ constructor(params: PageParameters);
/**
- * The page's name.
+ * Creates a new {@link Page}.
+ * @param params
+ * The page's parameters.
+ * @param assembler
+ * The page's assembler.
*/
- public get name(): string {
- let name = "";
+ constructor(params: PageParameters, assembler?: PageAssembler);
+ constructor(params: PageParameters, assembler?: PageAssembler) {
+ super();
+ let sections = new Map();
+ // Configure state
+ this.id = params.id;
+ this.path = params.path ?? params.id;
+ this.sections = sections;
+ this._plugins = null;
+ // Configure page assembler
+ if(assembler) {
+ this.__prepareAssembler(assembler);
+ }
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////
+ /// 1. Section Cloning //////////////////////////////////////////////////
+ ///////////////////////////////////////////////////////////////////////////
+
+
+ /**
+ * Clones the page.
+ * @returns
+ * The cloned page.
+ */
+ public clone(): Page
+
+ /**
+ * Clones the page.
+ * @param assembler
+ * The cloned page's assembler.
+ * @returns
+ * The cloned page.
+ */
+ public clone(assembler?: PageAssembler): Page;
+ public clone(assembler?: PageAssembler): Page {
+ assembler ??= new PageAssembler();
+ // Create page
+ let page = new Page({
+ id : this.id,
+ path : this.path
+ }, assembler);
+ // Clone sections
for(let section of this.sections.values()) {
- if(!section.isPrimary)
- continue;
- name = [...section.properties.values()]
- .filter(o => o.isPrimary && o.toString())
- .map(o => o.toString())
- .join(" - ");
- break;
+ let sectionAssembler = new SectionAssembler();
+ section.clone(sectionAssembler);
+ assembler.attachSection(sectionAssembler);
}
- return name || `Untitled ${ this.template }`;
- };
+ // Return
+ return page;
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////
+ /// 2. Plugin Management ////////////////////////////////////////////////
+ ///////////////////////////////////////////////////////////////////////////
/**
- * Creates a new {@link Page}.
- * @param template
- * The page's template.
+ * Attempts to install a plugin into the property.
+ * @param plugin
+ * The plugin to install.
+ * @returns
+ * True if the plugin was successfully installed, false otherwise.
*/
- constructor(template: PageTemplate) {
- // Init state
- this.instance = Crypto.randomUUID();
- this.id = template.id;
- this.template = template.name;
- // this.name = template.name;
- this.sections = new Map();
- // Init sections
- for(let s of template.sections) {
- let section = new PageSection(this, s);
- if(!this.sections.has(section.id)) {
- this.sections.set(section.id, section);
- } else {
- throw new Error(`Section '${
- section.id
- }' is defined twice in page '${
- this.id
- }'.`);
- }
+ public tryInstallPlugin(plugin: Plugin): boolean {
+ let result;
+ // Don't allocate manager until absolutely necessary
+ if(this._plugins === null) {
+ this._plugins = new PluginManager(this, this.root);
+ }
+ result = this._plugins.tryInstallPlugin(plugin);
+ // Deallocate manager if no plugins were installed
+ if(this._plugins.length === 0) {
+ this._plugins = null;
}
+ return result;
+ }
+
+ /**
+ * Attempts to install a list of plugins into the property.
+ * @param plugin
+ * The plugins to install.
+ * @returns
+ * True if all plugins were successfully installed, false otherwise.
+ */
+ public tryInstallPlugins(plugins: Plugin[]): boolean {
+ let result = true;
+ for(let plugin of plugins) {
+ result &&= this.tryInstallPlugin(plugin);
+ }
+ return result;
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////
+ /// 3. Assembler Preparation ////////////////////////////////////////////
+ ///////////////////////////////////////////////////////////////////////////
+
+
+ /**
+ * Prepares an assembler for the page.
+ * @returns
+ * The page's assembler.
+ * @remarks
+ * Page API use only. Do not use.
+ * @internal
+ */
+ public __prepareAssembler(): PageAssembler
+
+ /**
+ * Prepares an assembler for the page.
+ * @param assembler
+ * The assembler to use.
+ * @returns
+ * The page's assembler.
+ * @remarks
+ * Page API use only. Do not use.
+ * @internal
+ */
+ public __prepareAssembler(assembler?: PageAssembler): PageAssembler;
+ public __prepareAssembler(assembler: PageAssembler = new PageAssembler()): PageAssembler {
+ assembler.__injectAccessor({
+ page: this,
+ sections: this.sections as Map
+ });
+ return assembler;
}
}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Page/PageAccessor.ts b/src/cti_authoring_tool/src/assets/scripts/Page/PageAccessor.ts
new file mode 100644
index 0000000..bf93f18
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/Page/PageAccessor.ts
@@ -0,0 +1,16 @@
+import { Page } from "./Page";
+import { Section } from "./Section";
+
+export interface PageAccessor {
+
+ /**
+ * The page.
+ */
+ page: Page;
+
+ /**
+ * The page's sections.
+ */
+ sections: Map
+
+}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Page/PageAssembler.ts b/src/cti_authoring_tool/src/assets/scripts/Page/PageAssembler.ts
new file mode 100644
index 0000000..b19a5c6
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/Page/PageAssembler.ts
@@ -0,0 +1,152 @@
+import { Page } from "./Page"
+import { PageAccessor } from "./PageAccessor";
+import { SectionAssembler } from "./Section/SectionAssembler";
+
+export class PageAssembler {
+
+ /**
+ * The page's accessor.
+ */
+ private _accessor: PageAccessor | null;
+
+ /**
+ * The assembler's sections.
+ */
+ private _sectionAssemblers: Map;
+
+
+ /**
+ * The assembler's page.
+ */
+ public get page(): Page {
+ return this.accessor.page;
+ }
+
+ /**
+ * The assembler's sections.
+ */
+ public get sections(): ReadonlyMap {
+ return this._sectionAssemblers;
+ }
+
+ /**
+ * The page's accessor.
+ */
+ private get accessor(): PageAccessor {
+ if(this._accessor === null) {
+ throw new Error("Assembler is not configured with a page.");
+ }
+ return this._accessor;
+ }
+
+
+ /**
+ * Creates a new {@link PageAssembler}.
+ */
+ constructor() {
+ this._accessor = null;
+ this._sectionAssemblers = new Map();
+ }
+
+
+ /**
+ * Injects a page's private resources into the assembler.
+ * @param accessor
+ * The page's accessor.
+ * @remarks
+ * Page API use only. Do not use.
+ * @internal
+ */
+ public __injectAccessor(accessor: PageAccessor) {
+ this._accessor = accessor;
+ this._sectionAssemblers = new Map();
+ }
+
+ /**
+ * Adds a section to the page.
+ * @param asm
+ * The section's assembler.
+ */
+ public attachSection(asm: SectionAssembler) {
+ // Validate
+ if(this.includesSection(asm)) {
+ return;
+ }
+ // Detach existing child, if needed
+ let id = asm.section.id;
+ if(this.includesSection(id)) {
+ this.detachSection(id);
+ }
+ // Attach section
+ this.accessor.sections.set(id, asm.section);
+ this._sectionAssemblers.set(id, asm);
+ // Attach parent
+ asm.attachToPage(this);
+ }
+
+ /**
+ * Removes a section from the page.
+ * @param
+ * The section's id.
+ */
+ public detachSection(id: string): void;
+
+ /**
+ * Removes a section from the page.
+ * @param asm
+ * The section's assembler.
+ */
+ public detachSection(asm: SectionAssembler): void;
+ public detachSection(obj: string | SectionAssembler): void {
+ // Validate section
+ if(!this.includesSection(obj)) {
+ return;
+ }
+ if(typeof obj === "string") {
+ obj = this.sections.get(obj)!;
+ }
+ // Detach section
+ let id = obj.section.id;
+ this.accessor.sections.delete(id);
+ this._sectionAssemblers.delete(id);
+ // Detach parent
+ obj.detachFromPage();
+ }
+
+ /**
+ * Tests if the page includes a section.
+ * @param id
+ * The section's id.
+ * @returns
+ * True if the page includes the section, false otherwise.
+ */
+ public includesSection(id: string): boolean;
+
+ /**
+ * Tests if the page includes a section.
+ * @param asm
+ * The section's assembler.
+ * @returns
+ * True if the page includes the section, false otherwise.
+ */
+ public includesSection(asm: SectionAssembler): boolean;
+ public includesSection(obj: string | SectionAssembler): boolean;
+ public includesSection(obj: string | SectionAssembler): boolean {
+ let sections = this.accessor.sections;
+ // If string
+ if(typeof obj === "string") {
+ return sections.has(obj);
+ }
+ // If section
+ let id = obj.section.id;
+ if(!sections.has(id)) {
+ return false;
+ }
+ let sec = sections.get(id)!;
+ if(sec.instance !== obj.section.instance) {
+ return false;
+ }
+ return true;
+ }
+
+}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Page/PageElement.ts b/src/cti_authoring_tool/src/assets/scripts/Page/PageElement.ts
new file mode 100644
index 0000000..0860172
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/Page/PageElement.ts
@@ -0,0 +1,53 @@
+import * as Crypto from "@/assets/scripts/Utilities";
+import { EventEmitter } from "./Events/EventEmitter";
+
+export abstract class PageElement extends EventEmitter {
+
+ /**
+ * The page element's instance id.
+ */
+ public readonly instance: string;
+
+ /**
+ * The page element's parent.
+ */
+ protected _parent: PageElement | null;
+
+
+ /**
+ * The page element's root instance id.
+ */
+ public get rootInstance(): string {
+ return this.root.instance;
+ }
+
+ /**
+ * The page element's root.
+ */
+ protected get root(): PageElement {
+ let root: PageElement = this;
+ while(root._parent !== null) {
+ root = root._parent;
+ }
+ return root
+ }
+
+
+ /**
+ * Creates a new {@link PageElement}.
+ */
+ constructor() {
+ super();
+ this.instance = Crypto.randomUUID();
+ this._parent = null;
+ }
+
+
+ /**
+ * Clones the element.
+ * @returns
+ * The cloned element.
+ */
+ public abstract clone(): PageElement;
+
+}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Page/PageParameters.ts b/src/cti_authoring_tool/src/assets/scripts/Page/PageParameters.ts
new file mode 100644
index 0000000..e524f5a
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/Page/PageParameters.ts
@@ -0,0 +1,13 @@
+export type PageParameters = {
+
+ /**
+ * The page's id.
+ */
+ id: string,
+
+ /**
+ * The page's export path.
+ */
+ path?: string
+
+}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Page/PageSection.ts b/src/cti_authoring_tool/src/assets/scripts/Page/PageSection.ts
deleted file mode 100644
index 68be793..0000000
--- a/src/cti_authoring_tool/src/assets/scripts/Page/PageSection.ts
+++ /dev/null
@@ -1,252 +0,0 @@
-import { Page } from "./Page";
-import { Property } from "./Property";
-import { IPageSection } from "./IPagesSection";
-import { EventEmitter, String } from "../Utilities";
-import { PageSectionTemplate, Plugin } from "../AppConfiguration";
-
-export class PageSection extends EventEmitter implements IPageSection {
-
- /**
- * The section's id.
- */
- public readonly id: string;
-
- /**
- * The section's name.
- */
- public readonly name: string;
-
- /**
- * The section's layout.
- */
- public readonly layout: {
-
- /**
- * The number of rows in the section.
- */
- readonly rows: number,
-
- /**
- * The number of columns in the section.
- */
- readonly cols: number
-
- };
-
- /**
- * The section's properties.
- */
- public readonly properties: Map;
-
- /**
- * True if the section's name should be displayed, false otherwise.
- */
- public readonly isNameDisplayed: boolean;
-
- /**
- * The section's primary status.
- */
- public readonly isPrimary: boolean;
-
- /**
- * The page the section belongs to.
- */
- private readonly _page: Page;
-
- /**
- * The section's plugins.
- */
- private _plugins: Object[];
-
-
- /**
- * Creates a new {@link PageSection}.
- * @param page
- * The page the section belongs to.
- * @param template
- * The sections's template.
- */
- constructor(page: Page, template: PageSectionTemplate) {
- super();
- // Init state
- this.id = template?.id ?? String.formatId(template.name);
- this.name = template.name;
- this.layout = {
- rows: template.layout.rows,
- cols: template.layout.cols
- }
- this.properties = new Map();
- this.isNameDisplayed = template.is_name_displayed ?? true;
- this.isPrimary = template.is_primary ?? false;
- this._page = page;
- this._plugins = [];
- // Init properties
- for(let t of template.properties) {
- let prop = Property.create(this, t);
- if(!this.properties.has(prop.id)) {
- this.properties.set(prop.id, prop);
- } else {
- throw new Error(`Property '${
- prop.id
- }' is defined twice in section '${
- this.id
- }'.`);
- }
- }
- // Register plugins
- this.initializePlugins(template);
- }
-
- /**
- * Returns the instance id of the page the section belongs to.
- * @returns
- * The instance id of the page the section belongs to.
- */
- public getPageInstance(): string {
- return this._page.instance;
- }
-
-
- ///////////////////////////////////////////////////////////////////////////
- /// 1. IPageSection Methods /////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////
-
-
- /**
- * Adds an event listener to the section.
- * @param event
- * The event to subscribe to.
- * @param callback
- * The function to call once the event has fired.
- */
- public override on(event: string, callback: () => void): void {
- super.on(event, callback);
- }
-
- /**
- * Adds an event listener to the section that will be fired once and then
- * removed.
- * @param event
- * The event to subscribe to.
- * @param callback
- * The function to call once the event has fired.
- */
- public override once(event: string, callback: () => void): void {
- super.on(event, callback);
- }
-
- /**
- * Removes all event listeners associated with a given event. If no event
- * name is specified, all event listeners are removed.
- * @param event
- * The name of the event.
- */
- public override removeAllListeners(event?: string): void {
- super.removeAllListeners(event);
- }
-
-
- ///////////////////////////////////////////////////////////////////////////
- /// 2. Event Methods ////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////
-
-
- /**
- * Property mount behavior.
- * @param el
- * The property's HTML container.
- */
- public onMount(el: HTMLElement) {
- super.emit("mount", el);
- }
-
- /**
- * Property destroy behavior.
- */
- public onDestroy() {
- super.emit("destroy");
- }
-
- /**
- * Property selection behavior.
- * @param property
- * The property that was selected.
- */
- public onPropertySelect(property: Property) {
- super.emit("property-select", property);
- }
-
- /**
- * Property deselect behavior.
- * @param property
- * The property that was deselected.
- */
- public onPropertyDeselect(property: Property) {
- super.emit("property-deselect", property);
- }
-
- /**
- * Property update behavior.
- * @param property
- * The property that was updated.
- * @param newValue
- * The property's new value.
- * @param oldValue
- * The property's old value.
- */
- public onPropertyUpdate(property: Property, newValue: any, oldValue: any) {
- super.emit("property-update", property, newValue, oldValue);
- }
-
-
- ///////////////////////////////////////////////////////////////////////////
- /// 3. Plugins //////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////
-
-
- /**
- * Initializes all plugins from a section's template.
- * @param template
- * The section's template.
- */
- protected initializePlugins(template: PageSectionTemplate) {
- if(!template.plugins) {
- return;
- }
- for(let plugin of template.plugins) {
- this.tryRegisterPlugin(plugin);
- }
- }
-
- /**
- * Attempts to register a plugin with the section.
- * @param plugin
- * The plugin to register.
- * @returns
- * True if the plugin was successfully registered, false otherwise.
- */
- private tryRegisterPlugin(plugin: Plugin): boolean {
- // Ensure plugin is not already registered
- if(this._plugins.find(o => o.constructor === plugin.plugin)) {
- let name = plugin.plugin.name;
- throw new Error(`Plugin '${ name }' is already registered.`);
- }
- // Register plugin
- let p;
- try {
- if(plugin.options) {
- p = new plugin.plugin(this, plugin.options());
- } else {
- p = new plugin.plugin(this);
- }
- } catch(err) {
- let name = plugin.plugin.constructor.name;
- console.error(`Failed to initialize plugin '${ name }':`);
- console.error(err);
- return false;
- }
- this._plugins.push(p);
- return true;
- }
-
-}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Page/Plugins/Plugin.ts b/src/cti_authoring_tool/src/assets/scripts/Page/Plugins/Plugin.ts
new file mode 100644
index 0000000..7d02b55
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/Page/Plugins/Plugin.ts
@@ -0,0 +1,6 @@
+import { PluginModule } from "./PluginModule";
+
+export interface Plugin {
+ module : PluginModule;
+ options? : () => any;
+}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Page/Plugins/PluginConfiguration.ts b/src/cti_authoring_tool/src/assets/scripts/Page/Plugins/PluginConfiguration.ts
new file mode 100644
index 0000000..a1cd4c9
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/Page/Plugins/PluginConfiguration.ts
@@ -0,0 +1,9 @@
+export class PluginConfiguration {
+
+ /**
+ * A function that returns an object's reactive proxy. This must be
+ * specified if plugins are used in a reactive context.
+ */
+ public static makeReactive: ((o: O) => O) | undefined;
+
+}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Page/Plugins/PluginInstance.ts b/src/cti_authoring_tool/src/assets/scripts/Page/Plugins/PluginInstance.ts
new file mode 100644
index 0000000..dab48d5
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/Page/Plugins/PluginInstance.ts
@@ -0,0 +1,6 @@
+import { Plugin } from "./Plugin";
+
+export type PluginInstance = {
+ plugin : Plugin,
+ instance : Object
+};
diff --git a/src/cti_authoring_tool/src/assets/scripts/Page/Plugins/PluginManager.ts b/src/cti_authoring_tool/src/assets/scripts/Page/Plugins/PluginManager.ts
new file mode 100644
index 0000000..c093901
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/Page/Plugins/PluginManager.ts
@@ -0,0 +1,70 @@
+import { Plugin } from "./Plugin";
+import { PageElement } from "../PageElement";
+import { PluginInstance } from "./PluginInstance";
+import { PluginConfiguration } from "./PluginConfiguration";
+
+export class PluginManager extends Array> {
+
+ /**
+ * The page element.
+ */
+ public readonly element: T;
+
+ /**
+ * The page's root element.
+ */
+ private readonly _root: PageElement;
+
+
+ /**
+ * Creates a new {@link PluginManager}.
+ * @param element
+ * The page element.
+ * @param root
+ * The page's root element.
+ */
+ constructor(element: T, root: PageElement) {
+ super();
+ this.element = element;
+ this._root = root;
+ if(PluginConfiguration.makeReactive) {
+ this.element = PluginConfiguration.makeReactive(this.element);
+ this._root = PluginConfiguration.makeReactive(this._root);
+ }
+ }
+
+
+ /**
+ * Attempts to install a plugin.
+ * @param plugin
+ * The plugin to install.
+ * @returns
+ * True if the plugin was successfully installed, false otherwise.
+ */
+ public tryInstallPlugin(plugin: Plugin): boolean;
+ public tryInstallPlugin(plugin: Plugin): boolean {
+ // Ensure plugin is not already installed
+ let name = plugin.module.name;
+ if(this.find(o => o.plugin.module.name === name)) {
+ throw new Error(`Plugin '${ name }' is already installed.`);
+ }
+ // Instantiate plugin
+ let instance;
+ try {
+ if(plugin.options) {
+ instance = new plugin.module(this.element, this._root, plugin.options());
+ } else {
+ instance = new plugin.module(this.element, this._root);
+ }
+ } catch(err) {
+ let name = plugin.module.name;
+ console.error(`Failed to install plugin '${ name }':`);
+ console.error(err);
+ return false;
+ }
+ // Install plugin
+ this.push({ plugin, instance });
+ return true;
+ }
+
+}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Page/Plugins/PluginModule.ts b/src/cti_authoring_tool/src/assets/scripts/Page/Plugins/PluginModule.ts
new file mode 100644
index 0000000..f63d7f8
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/Page/Plugins/PluginModule.ts
@@ -0,0 +1,3 @@
+import { PageElement } from "../PageElement";
+
+export type PluginModule = new (property: T, root: PageElement, options?: any) => any
diff --git a/src/cti_authoring_tool/src/assets/scripts/Page/Plugins/index.ts b/src/cti_authoring_tool/src/assets/scripts/Page/Plugins/index.ts
new file mode 100644
index 0000000..4678e8b
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/Page/Plugins/index.ts
@@ -0,0 +1,4 @@
+export * from "./Plugin";
+export * from "./PluginInstance";
+export * from "./PluginManager";
+export * from "./PluginModule";
diff --git a/src/cti_authoring_tool/src/assets/scripts/Page/Property/AtomicProperty/Alignment.ts b/src/cti_authoring_tool/src/assets/scripts/Page/Property/AtomicProperty/Alignment.ts
new file mode 100644
index 0000000..44961c6
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/Page/Property/AtomicProperty/Alignment.ts
@@ -0,0 +1,111 @@
+export enum Alignment {
+
+ /**
+ * Top left alignment
+ *
+ * @example
+ *
+ * | X . . |
+ * | . . . |
+ * | . . . |
+ *
+ */
+ TopLeft,
+
+ /**
+ * Top center alignment
+ *
+ * @example
+ *
+ * | . X . |
+ * | . . . |
+ * | . . . |
+ *
+ */
+ TopCenter,
+
+ /**
+ * Top right alignment
+ *
+ * @example
+ *
+ * | . . X |
+ * | . . . |
+ * | . . . |
+ *
+ */
+ TopRight,
+
+ /**
+ * Middle left alignment
+ *
+ * @example
+ *
+ * | . . . |
+ * | X . . |
+ * | . . . |
+ *
+ */
+ MiddleLeft,
+
+ /**
+ * Middle center alignment
+ *
+ * @example
+ *
+ * | . . . |
+ * | . X . |
+ * | . . . |
+ *
+ */
+ MiddleCenter,
+
+ /**
+ * Middle right alignment
+ *
+ * @example
+ *
+ * | . . . |
+ * | . . X |
+ * | . . . |
+ *
+ */
+ MiddleRight,
+
+ /**
+ * Bottom left alignment
+ *
+ * @example
+ *
+ * | . . . |
+ * | . . . |
+ * | X . . |
+ *
+ */
+ BottomLeft,
+
+ /**
+ * Bottom center alignment
+ *
+ * @example
+ *
+ * | . . . |
+ * | . . . |
+ * | . X . |
+ *
+ */
+ BottomCenter,
+
+ /**
+ * Bottom right alignment
+ *
+ * @example
+ *
+ * | . . . |
+ * | . . . |
+ * | . . X |
+ *
+ */
+ BottomRight
+
+}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Page/Property/AtomicProperty/AtomicProperty.ts b/src/cti_authoring_tool/src/assets/scripts/Page/Property/AtomicProperty/AtomicProperty.ts
index d79ec93..0f0ebe0 100644
--- a/src/cti_authoring_tool/src/assets/scripts/Page/Property/AtomicProperty/AtomicProperty.ts
+++ b/src/cti_authoring_tool/src/assets/scripts/Page/Property/AtomicProperty/AtomicProperty.ts
@@ -1,9 +1,10 @@
import { Property } from "..";
-import { PageSection } from "../../PageSection";
-import { IAtomicProperty } from "./IAtomicProperty";
-import { Alignment, AtomicPropertyTemplate } from "../../../AppConfiguration";
+import { Alignment } from "./Alignment";
+import { PropertyAssembler } from "../PropertyAssembler";
+import { AtomicPropertyMetric } from "./AtomicPropertyMetric";
+import { AtomicPropertyParameters } from "./AtomicPropertyParameters";
-export abstract class AtomicProperty extends Property implements IAtomicProperty {
+export abstract class AtomicProperty extends Property {
/**
* If the property is required or not.
@@ -18,61 +19,93 @@ export abstract class AtomicProperty extends Property implements IAtomicProperty
/**
* The property's metrics.
*/
- protected _metrics: any[];
+ protected _metrics: Map;
+ /**
+ * The property's metrics.
+ */
+ public get metrics(): ReadonlyMap {
+ return this._metrics;
+ }
+
+
+ /**
+ * Creates a new {@link AtomicProperty}.
+ * @param params
+ * The property's parameters.
+ */
+ constructor(params: AtomicPropertyParameters);
+
/**
* Creates a new {@link AtomicProperty}.
- * @param section
- * The property's section.
- * @param template
- * The property's template.
+ * @param params
+ * The property's parameters.
+ * @param assembler
+ * The property's assembler.
*/
- constructor(section: PageSection, template: AtomicPropertyTemplate) {
- super(section, template);
- this.required = template.required ?? true;
- this.alignment = template.alignment ?? Alignment.TopLeft;
- this._metrics = [];
+ constructor(params: AtomicPropertyParameters, assembler?: PropertyAssembler);
+ constructor(params: AtomicPropertyParameters, assembler?: PropertyAssembler) {
+ super(params, assembler);
+ this.required = params.required ?? false;
+ this.alignment = params.alignment ?? Alignment.TopLeft;
+ this._metrics = new Map();
}
///////////////////////////////////////////////////////////////////////////
- /// 1. IAtomicProperty Methods //////////////////////////////////////////
+ /// 1. Metric Management ////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
/**
* Registers a property metric.
- * @param name
- * The metric's name.
- * @param metric
- * The metric.
+ * @param id
+ * The metric's id.
+ * @param text
+ * The metric's text.
+ * @param value
+ * The metric's initial value.
+ */
+ public registerMetric(id: string, text: string, value: string | number | boolean): void {
+ this._metrics.set(id, { text, value });
+ }
+
+ /**
+ * Updates a property metric.
+ * @param id
+ * The metric's id.
+ * @param value
+ * The metric's new value.
*/
- public registerMetric(name: string, metric: () => any): void {
- // TODO: Implement metric registration
- throw new Error("Method not implemented.");
+ public updateMetric(id: string, value: string | number | boolean) {
+ if(!this._metrics.has(id)) {
+ throw new Error(`'${ id }' is not a registered metric.`);
+ } else {
+ this._metrics.get(id)!.value = value;
+ }
}
///////////////////////////////////////////////////////////////////////////
- /// 2. Event Methods ////////////////////////////////////////////////////
+ /// 2. Property Cloning /////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
-
+
/**
- * Property select behavior.
+ * Clones the property.
+ * @returns
+ * The cloned property.
*/
- public onSelect() {
- super.emit("select");
- this._section.onPropertySelect(this);
- }
+ public abstract override clone(): AtomicProperty;
/**
- * Property deselect behavior.
+ * Clones the property.
+ * @param assembler
+ * The cloned property's assembler.
+ * @returns
+ * The cloned property.
*/
- public onDeselect() {
- super.emit("deselect");
- this._section.onPropertyDeselect(this);
- }
+ public abstract override clone(assembler?: PropertyAssembler): AtomicProperty;
}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Page/Property/AtomicProperty/AtomicPropertyMetric.ts b/src/cti_authoring_tool/src/assets/scripts/Page/Property/AtomicProperty/AtomicPropertyMetric.ts
new file mode 100644
index 0000000..ab4b6fc
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/Page/Property/AtomicProperty/AtomicPropertyMetric.ts
@@ -0,0 +1,13 @@
+export interface AtomicPropertyMetric {
+
+ /**
+ * The metric's text.
+ */
+ readonly text: string,
+
+ /**
+ * The metric's value.
+ */
+ value: string | number | boolean
+
+}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Page/Property/AtomicProperty/AtomicPropertyParameters.ts b/src/cti_authoring_tool/src/assets/scripts/Page/Property/AtomicProperty/AtomicPropertyParameters.ts
new file mode 100644
index 0000000..fe563fc
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/Page/Property/AtomicProperty/AtomicPropertyParameters.ts
@@ -0,0 +1,16 @@
+import { PropertyParameters } from "../PropertyParameters";
+import { Alignment } from "./Alignment";
+
+export interface AtomicPropertyParameters extends PropertyParameters {
+
+ /**
+ * If the property is required or not.
+ */
+ required?: boolean;
+
+ /**
+ * The property's alignment.
+ */
+ alignment?: Alignment;
+
+}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Page/Property/AtomicProperty/IAtomicProperty.ts b/src/cti_authoring_tool/src/assets/scripts/Page/Property/AtomicProperty/IAtomicProperty.ts
deleted file mode 100644
index 31907f6..0000000
--- a/src/cti_authoring_tool/src/assets/scripts/Page/Property/AtomicProperty/IAtomicProperty.ts
+++ /dev/null
@@ -1,76 +0,0 @@
-import { Alignment } from "@/assets/scripts/AppConfiguration";
-import { IProperty, PropertyEvents } from "../IProperty";
-
-export interface IAtomicProperty extends IProperty {
-
- /**
- * If the property is required or not.
- */
- readonly required: boolean;
-
- /**
- * The property's alignment.
- */
- readonly alignment: Alignment;
-
-
- ///////////////////////////////////////////////////////////////////////////
- // 1. Metric Registration ///////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////
-
-
- /**
- * Registers a property metric.
- * @param name
- * The metric's name.
- * @param metric
- * The metric.
- */
- registerMetric(name: string, metric: () => any): void;
-
-
- ///////////////////////////////////////////////////////////////////////////
- // 2. Events ////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////
-
-
- /**
- * Adds an event listener to the property.
- * @param event
- * The event to subscribe to.
- * @param callback
- * The function to call once the event has fired.
- */
- on(event: K, callback: AtomicPropertyEvents[K]): void;
-
- /**
- * Adds an event listener to the property that will be fired once and then
- * removed.
- * @param event
- * The event to subscribe to.
- * @param callback
- * The function to call once the event has fired.
- */
- once(event: K, callback: AtomicPropertyEvents[K]): void;
-
- /**
- * Removes all event listeners associated with a given event. If no event
- * name is specified, all event listeners are removed.
- * @param event
- * The name of the event.
- */
- removeAllListeners(event?: K): void;
-
-}
-
-
-///////////////////////////////////////////////////////////////////////////////
-// Internal Types ///////////////////////////////////////////////////////////
-///////////////////////////////////////////////////////////////////////////////
-
-
-// Event types
-export interface AtomicPropertyEvents extends PropertyEvents {
- "select" : () => void,
- "deselect" : () => void
-}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Page/Property/AtomicProperty/index.ts b/src/cti_authoring_tool/src/assets/scripts/Page/Property/AtomicProperty/index.ts
new file mode 100644
index 0000000..7eec062
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/Page/Property/AtomicProperty/index.ts
@@ -0,0 +1,3 @@
+export * from "./Alignment";
+export * from "./AtomicProperty";
+export * from "./AtomicPropertyParameters";
\ No newline at end of file
diff --git a/src/cti_authoring_tool/src/assets/scripts/Page/Property/BasicTableProperty/BasicTableProperty.ts b/src/cti_authoring_tool/src/assets/scripts/Page/Property/BasicTableProperty/BasicTableProperty.ts
index 878a203..7320f00 100644
--- a/src/cti_authoring_tool/src/assets/scripts/Page/Property/BasicTableProperty/BasicTableProperty.ts
+++ b/src/cti_authoring_tool/src/assets/scripts/Page/Property/BasicTableProperty/BasicTableProperty.ts
@@ -1,56 +1,79 @@
-import { PageSection } from "../../PageSection";
-import { TabularProperty } from "..";
-import { IBasicTableProperty } from "./IBasicTableProperty";
-import { BasicTablePropertyTemplate, TabularPropertyRowValue } from "../../../AppConfiguration";
+import { BasicTablePropertyLayout } from "./BasicTablePropertyLayout";
+import { BasicTablePropertyParameters, TabularProperty, TabularPropertyAssembler } from "..";
-export class BasicTableProperty extends TabularProperty implements IBasicTableProperty {
+export class BasicTableProperty extends TabularProperty {
/**
* The table's layout.
*/
- public readonly layout: {
-
- /**
- * The table's number of columns.
- */
- readonly cols: number;
-
- }
+ public readonly layout: BasicTablePropertyLayout;
/**
* Creates a new {@link BasicTableProperty}.
- * @param section
- * The property's section.
- * @param template
- * The property's template.
- * @throws { Error }
- * If `template` defines a non-atomic property.
+ * @param params
+ * The property's parameters.
*/
- constructor(section: PageSection, template: BasicTablePropertyTemplate);
+ constructor(params: BasicTablePropertyParameters);
/**
* Creates a new {@link BasicTableProperty}.
- * @param section
- * The property's section.
- * @param template
- * The property's template.
- * @param value
- * The property's value.
- * @throws { Error }
- * If `template` defines a non-atomic property.
+ * @param params
+ * The property's parameters.
+ * @param assembler
+ * The property's assembler.
*/
- constructor(section: PageSection, template: BasicTablePropertyTemplate, value: TabularPropertyRowValue[])
- constructor(section: PageSection, template: BasicTablePropertyTemplate, value?: TabularPropertyRowValue[]) {
- if(value === undefined) {
- super(section, template);
- } else {
- super(section, template, value);
- }
+ constructor(params: BasicTablePropertyParameters, assembler?: TabularPropertyAssembler);
+ constructor(params: BasicTablePropertyParameters, assembler?: TabularPropertyAssembler) {
+ super(params, assembler);
this.layout = {
- cols: template.layout.cols
+ cols: params.layout.cols
+ }
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////
+ /// 1. Property Cloning /////////////////////////////////////////////////
+ ///////////////////////////////////////////////////////////////////////////
+
+
+ /**
+ * Clones the property.
+ * @returns
+ * The cloned property.
+ */
+ public override clone(): BasicTableProperty
+
+ /**
+ * Clones the property.
+ * @param assembler
+ * The cloned property's assembler.
+ * @returns
+ * The cloned property.
+ */
+ public override clone(assembler?: TabularPropertyAssembler): BasicTableProperty {
+ // Create property
+ let prop = new BasicTableProperty({
+ id : this.id,
+ name : this.name,
+ path : this.path,
+ link : this.link,
+ row : this.row,
+ col : this.col,
+ layout: {
+ cols : this.layout.cols
+ }
+ }, assembler);
+ // Clone values
+ for(let [id, row] of this._value) {
+ prop.insertRow([id, row.map(o => o.clone())]);
}
- this.initializePlugins(template);
+ // Clone plugins
+ this._plugins?.forEach(({ plugin }) => {
+ prop.tryInstallPlugin(plugin);
+ });
+ // Return
+ return prop;
}
}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Page/Property/BasicTableProperty/BasicTablePropertyLayout.ts b/src/cti_authoring_tool/src/assets/scripts/Page/Property/BasicTableProperty/BasicTablePropertyLayout.ts
new file mode 100644
index 0000000..5544831
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/Page/Property/BasicTableProperty/BasicTablePropertyLayout.ts
@@ -0,0 +1,8 @@
+export interface BasicTablePropertyLayout {
+
+ /**
+ * The table's number of columns.
+ */
+ readonly cols: number;
+
+}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Page/Property/BasicTableProperty/BasicTablePropertyParameters.ts b/src/cti_authoring_tool/src/assets/scripts/Page/Property/BasicTableProperty/BasicTablePropertyParameters.ts
new file mode 100644
index 0000000..3da8ebe
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/Page/Property/BasicTableProperty/BasicTablePropertyParameters.ts
@@ -0,0 +1,17 @@
+import { PropertyParameters } from "../PropertyParameters";
+
+export interface BasicTablePropertyParameters extends PropertyParameters {
+
+ /**
+ * The table's layout.
+ */
+ layout: {
+
+ /**
+ * The table's number of columns.
+ */
+ cols: number;
+
+ }
+
+}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Page/Property/BasicTableProperty/IBasicTableProperty.ts b/src/cti_authoring_tool/src/assets/scripts/Page/Property/BasicTableProperty/IBasicTableProperty.ts
deleted file mode 100644
index 74010ed..0000000
--- a/src/cti_authoring_tool/src/assets/scripts/Page/Property/BasicTableProperty/IBasicTableProperty.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-import { ITabularProperty } from "../TabularProperty/ITabularProperty";
-
-export interface IBasicTableProperty extends ITabularProperty {
-
- /**
- * The table's layout.
- */
- readonly layout: {
-
- /**
- * The table's number of columns.
- */
- readonly cols: number;
-
- }
-
-}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Page/Property/BasicTableProperty/index.ts b/src/cti_authoring_tool/src/assets/scripts/Page/Property/BasicTableProperty/index.ts
new file mode 100644
index 0000000..b6ef921
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/Page/Property/BasicTableProperty/index.ts
@@ -0,0 +1,2 @@
+export * from "./BasicTableProperty";
+export * from "./BasicTablePropertyParameters";
diff --git a/src/cti_authoring_tool/src/assets/scripts/Page/Property/ComplexTableProperty/ComplexTableProperty.ts b/src/cti_authoring_tool/src/assets/scripts/Page/Property/ComplexTableProperty/ComplexTableProperty.ts
index 56a4a07..efb105d 100644
--- a/src/cti_authoring_tool/src/assets/scripts/Page/Property/ComplexTableProperty/ComplexTableProperty.ts
+++ b/src/cti_authoring_tool/src/assets/scripts/Page/Property/ComplexTableProperty/ComplexTableProperty.ts
@@ -1,92 +1,64 @@
-import { PageSection } from "../../PageSection";
-import { IComplexTableProperty } from "./IComplexTableProperty";
-import { AtomicProperty, TabularProperty } from "..";
-import { ComplexTablePropertyTemplate, TabularPropertyRowValue } from "../../../AppConfiguration";
-export class ComplexTableProperty extends TabularProperty implements IComplexTableProperty {
+import { ComplexTablePropertyLayout } from "./ComplexTablePropertyLayout";
+import {
+ AtomicProperty,
+ ComplexTablePropertyParameters,
+ TabularProperty,
+ TabularPropertyAssembler
+} from "..";
+
+export class ComplexTableProperty extends TabularProperty {
/**
* The data region's layout.
*/
- public readonly layout: {
-
- /**
- * The data region's summary template.
- */
- readonly summary: string;
-
- /**
- * The number of rows in each data region.
- */
- readonly rows: number;
-
- /**
- * The number of columns in each data region.
- */
- readonly cols: number;
-
- }
+ public readonly layout: ComplexTablePropertyLayout
/**
* The table row's collapsed state.
- * @remarks
- * Because the overridden `insertRow()` is used in the base constructor,
- * `collapsed` is accessed before it's defined. To avoid this, `collapsed`
- * is backed by `_collapsed` which is initialized on first access of
- * `collapsed`.
*/
- public get collapsed(): Map {
- if(this._collapsed === undefined) {
- this._collapsed = new Map();
- }
- return this._collapsed;
- }
+ private _collapsed: Map;
+
/**
- * The table row's (internal) collapsed state.
+ * The table row's collapsed state.
*/
- // @ts-ignore
- private _collapsed: Map;
+ public get collapsed(): ReadonlyMap {
+ return this._collapsed;
+ }
/**
* Creates a new {@link ComplexTableProperty}.
- * @param section
- * The property's section.
- * @param template
- * The property's template.
- * @throws { Error }
- * If `template` defines a non-atomic property.
+ * @param params
+ * The property's parameters.
*/
- constructor(section: PageSection, template: ComplexTablePropertyTemplate);
+ constructor(params: ComplexTablePropertyParameters);
/**
* Creates a new {@link ComplexTableProperty}.
- * @param section
- * The property's section.
- * @param template
- * The property's template.
- * @param value
- * The property' value.
- * @throws { Error }
- * If `template` defines a non-atomic property.
+ * @param params
+ * The property's parameters.
+ * @param assembler
+ * The property's assembler.
*/
- constructor(section: PageSection, template: ComplexTablePropertyTemplate, value: TabularPropertyRowValue[]);
- constructor(section: PageSection, template: ComplexTablePropertyTemplate, value?: TabularPropertyRowValue[]) {
- if(value === undefined) {
- super(section, template);
- } else {
- super(section, template, value);
- }
+ constructor(params: ComplexTablePropertyParameters, assembler?: TabularPropertyAssembler);
+ constructor(params: ComplexTablePropertyParameters, assembler?: TabularPropertyAssembler) {
+ super(params, assembler);
this.layout = {
- summary: template.layout.summary,
- rows: template.layout.rows,
- cols: template.layout.cols
+ summary: params.layout.summary,
+ rows: params.layout.rows,
+ cols: params.layout.cols
};
- this.initializePlugins(template);
+ this._collapsed = new Map();
}
+ ///////////////////////////////////////////////////////////////////////////
+ /// 1. Row Collapse Management //////////////////////////////////////////
+ ///////////////////////////////////////////////////////////////////////////
+
+
/**
* Inserts a row into the table property.
* @param row
@@ -94,11 +66,11 @@ export class ComplexTableProperty extends TabularProperty implements IComplexTab
* @param index
* The row's index.
* @throws { Error }
- * If `row` does not match the table's property schema.
+ * If `row` does not match the table's structure.
*/
public override insertRow(row: [string, AtomicProperty[]], index?: number) {
// Update collapsed state
- this.collapsed.set(row[0], true);
+ this._collapsed.set(row[0], true);
// Insert row
super.insertRow(row, index);
}
@@ -123,10 +95,10 @@ export class ComplexTableProperty extends TabularProperty implements IComplexTab
public override deleteRow(_: string | number): boolean {
// Update collapsed state
if(typeof _ === "number") {
- _ = [...this.value.keys()][_];
+ _ = [...this._value.keys()][_];
}
if(_ !== undefined) {
- this.collapsed.delete(_);
+ this._collapsed.delete(_);
}
// Delete row
return super.deleteRow(_);
@@ -140,9 +112,57 @@ export class ComplexTableProperty extends TabularProperty implements IComplexTab
* True to collapse, false to uncollapse.
*/
public setRowCollapse(id: string, collapse: boolean) {
- if(this.collapsed.has(id)) {
- this.collapsed.set(id, collapse);
+ if(this._collapsed.has(id)) {
+ this._collapsed.set(id, collapse);
+ }
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////
+ /// 1. Property Cloning /////////////////////////////////////////////////
+ ///////////////////////////////////////////////////////////////////////////
+
+
+ /**
+ * Clones the property.
+ * @returns
+ * The cloned property.
+ */
+ public override clone(): ComplexTableProperty
+
+ /**
+ * Clones the property.
+ * @param assembler
+ * The cloned property's assembler.
+ * @returns
+ * The cloned property.
+ */
+ public override clone(assembler?: TabularPropertyAssembler): ComplexTableProperty {
+ // Create property
+ let prop = new ComplexTableProperty({
+ id : this.id,
+ name : this.name,
+ path : this.path,
+ link : this.link,
+ row : this.row,
+ col : this.col,
+ layout: {
+ cols : this.layout.cols,
+ rows : this.layout.rows,
+ summary : this.layout.summary
+ }
+ }, assembler);
+ // Clone values
+ for(let [id, row] of this._value) {
+ prop.insertRow([id, row.map(o => o.clone())]);
+ prop.setRowCollapse(id, this._collapsed.get(id)!);
}
+ // Clone plugins
+ this._plugins?.forEach(({ plugin }) => {
+ prop.tryInstallPlugin(plugin);
+ });
+ // Return
+ return prop;
}
}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Page/Property/ComplexTableProperty/ComplexTablePropertyLayout.ts b/src/cti_authoring_tool/src/assets/scripts/Page/Property/ComplexTableProperty/ComplexTablePropertyLayout.ts
new file mode 100644
index 0000000..f030800
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/Page/Property/ComplexTableProperty/ComplexTablePropertyLayout.ts
@@ -0,0 +1,18 @@
+export interface ComplexTablePropertyLayout {
+
+ /**
+ * The data region's summary template.
+ */
+ readonly summary: string;
+
+ /**
+ * The number of rows in each data region.
+ */
+ readonly rows: number;
+
+ /**
+ * The number of columns in each data region.
+ */
+ readonly cols: number;
+
+}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Page/Property/ComplexTableProperty/ComplexTablePropertyParameters.ts b/src/cti_authoring_tool/src/assets/scripts/Page/Property/ComplexTableProperty/ComplexTablePropertyParameters.ts
new file mode 100644
index 0000000..680451e
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/Page/Property/ComplexTableProperty/ComplexTablePropertyParameters.ts
@@ -0,0 +1,27 @@
+import { PropertyParameters } from "../PropertyParameters";
+
+export interface ComplexTablePropertyParameters extends PropertyParameters {
+
+ /**
+ * The data region's layout.
+ */
+ layout: {
+
+ /**
+ * The data region's summary template.
+ */
+ summary: string;
+
+ /**
+ * The number of rows in each data region.
+ */
+ rows: number;
+
+ /**
+ * The number of columns in each data region.
+ */
+ cols: number;
+
+ }
+
+}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Page/Property/ComplexTableProperty/IComplexTableProperty.ts b/src/cti_authoring_tool/src/assets/scripts/Page/Property/ComplexTableProperty/IComplexTableProperty.ts
deleted file mode 100644
index 43d7acd..0000000
--- a/src/cti_authoring_tool/src/assets/scripts/Page/Property/ComplexTableProperty/IComplexTableProperty.ts
+++ /dev/null
@@ -1,92 +0,0 @@
-import { ITabularProperty, TabularPropertyEvents } from "../TabularProperty/ITabularProperty";
-
-export interface IComplexTableProperty extends ITabularProperty {
-
- /**
- * The data region's layout.
- */
- readonly layout: {
-
- /**
- * The data region's summary template.
- */
- readonly summary: string;
-
- /**
- * The number of rows in each data region.
- */
- readonly rows: number;
-
- /**
- * The number of columns in each data region.
- */
- readonly cols: number;
-
- }
-
- /**
- * The table row's collapsed state.
- */
- get collapsed(): ReadonlyMap
-
-
- ///////////////////////////////////////////////////////////////////////////
- // 1. Value Manipulation ////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////
-
-
- /**
- * Collapses a row.
- * @param id
- * The row's id.
- * @param collapse
- * True to collapse, false to uncollapse.
- */
- setRowCollapse(id: string, collapse: boolean): void;
-
-
- ///////////////////////////////////////////////////////////////////////////
- // 2. Events ////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////
-
-
- /**
- * Adds an event listener to the property.
- * @param event
- * The event to subscribe to.
- * @param callback
- * The function to call once the event has fired.
- */
- on(event: K, callback: ComplexTablePropertyEvents[K]): void;
-
- /**
- * Adds an event listener to the property that will be fired once and then
- * removed.
- * @param event
- * The event to subscribe to.
- * @param callback
- * The function to call once the event has fired.
- */
- once(event: K, callback: ComplexTablePropertyEvents[K]): void;
-
- /**
- * Removes all event listeners associated with a given event. If no event
- * name is specified, all event listeners are removed.
- * @param event
- * The name of the event.
- */
- removeAllListeners(event?: K): void;
-
-}
-
-
-///////////////////////////////////////////////////////////////////////////////
-// Internal Types ///////////////////////////////////////////////////////////
-///////////////////////////////////////////////////////////////////////////////
-
-
-// Event types
-export interface ComplexTablePropertyEvents extends TabularPropertyEvents {
- "row-collapse" : (id: string) => void,
- "row-uncollapse" : (id: string) => void
-}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Page/Property/ComplexTableProperty/index.ts b/src/cti_authoring_tool/src/assets/scripts/Page/Property/ComplexTableProperty/index.ts
new file mode 100644
index 0000000..a75e98f
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/Page/Property/ComplexTableProperty/index.ts
@@ -0,0 +1,4 @@
+export * from "./ComplexTableProperty";
+export * from "./ComplexTablePropertyParameters";
+export * from "./FormattedText";
+export * from "./SummaryParser";
diff --git a/src/cti_authoring_tool/src/assets/scripts/Page/Property/DateTimeProperty/DateProperty.ts b/src/cti_authoring_tool/src/assets/scripts/Page/Property/DateTimeProperty/DateProperty.ts
new file mode 100644
index 0000000..ce6b122
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/Page/Property/DateTimeProperty/DateProperty.ts
@@ -0,0 +1,68 @@
+import { DateTimeProperty } from "./DateTimeProperty";
+import { PropertyAssembler } from "../PropertyAssembler";
+import { AtomicPropertyParameters } from "../AtomicProperty/AtomicPropertyParameters";
+
+export class DateProperty extends DateTimeProperty {
+
+ /**
+ * Creates a new {@link DateProperty}.
+ * @param params
+ * The property's parameters.
+ */
+ constructor(params: AtomicPropertyParameters);
+
+ /**
+ * Creates a new {@link DateProperty}.
+ * @param params
+ * The property's parameters.
+ * @param assembler
+ * The property's assembler.
+ */
+ constructor(params: AtomicPropertyParameters, assembler?: PropertyAssembler);
+ constructor(params: AtomicPropertyParameters, assembler?: PropertyAssembler) {
+ super(params, assembler);
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////
+ /// 1. Property Cloning /////////////////////////////////////////////////
+ ///////////////////////////////////////////////////////////////////////////
+
+
+ /**
+ * Clones the property.
+ * @returns
+ * The cloned property.
+ */
+ public override clone(): DateProperty
+
+ /**
+ * Clones the property.
+ * @param assembler
+ * The cloned property's assembler.
+ * @returns
+ * The cloned property.
+ */
+ public override clone(assembler?: PropertyAssembler): DateProperty {
+ // Create property
+ let prop = new DateProperty({
+ id : this.id,
+ name : this.name,
+ path : this.path,
+ link : this.link,
+ row : this.row,
+ col : this.col,
+ required : this.required,
+ alignment : this.alignment
+ }, assembler);
+ // Clone values
+ prop.value = this.value;
+ // Clone plugins
+ this._plugins?.forEach(({ plugin }) => {
+ prop.tryInstallPlugin(plugin)
+ });
+ // Return
+ return prop;
+ }
+
+}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Page/Property/DateTimeProperty/DateTimeProperty.ts b/src/cti_authoring_tool/src/assets/scripts/Page/Property/DateTimeProperty/DateTimeProperty.ts
index 68e3d1d..53a440d 100644
--- a/src/cti_authoring_tool/src/assets/scripts/Page/Property/DateTimeProperty/DateTimeProperty.ts
+++ b/src/cti_authoring_tool/src/assets/scripts/Page/Property/DateTimeProperty/DateTimeProperty.ts
@@ -1,103 +1,165 @@
-import { PageSection } from "../../PageSection";
import { AtomicProperty } from "..";
-import { IDateTimeProperty } from "./IDateTimeProperty";
-import { DateTimePropertyTemplate } from "@/assets/scripts/AppConfiguration";
+import { PropertyAssembler } from "../PropertyAssembler";
+import { Plugin, PluginManager } from "../../Plugins";
+import { AtomicPropertyParameters } from "../AtomicProperty/AtomicPropertyParameters";
-export class DateTimeProperty extends AtomicProperty implements IDateTimeProperty {
+export class DateTimeProperty extends AtomicProperty {
/**
* The property's value.
*/
- public value: Date | null;
+ private _value: Date | null;
+
+ /**
+ * The property's plugin manager.
+ */
+ protected _plugins: PluginManager | null;
/**
- * Creates a new {@link DateTimeProperty}.
- * @param section
- * The property's section.
- * @param template
- * The property's template.
+ * The property value's getter.
*/
- constructor(section: PageSection, template: DateTimePropertyTemplate);
+ public get value(): Date | null {
+ return this._value;
+ }
/**
- * Creates a new {@link DateTimeProperty}.
- * @param section
- * The property's section.
- * @param template
- * The property's template.
- * @param value
- * The property's value.
+ * The property value's setter.
*/
- constructor(section: PageSection, template: DateTimePropertyTemplate, value: string);
- constructor(section: PageSection, template: DateTimePropertyTemplate, value?: string) {
- super(section, template);
- this.value = null;
- if(value !== undefined) {
- this.setValue(value);
- } else if(template.default !== undefined) {
- this.setValue(template.default);
+ public set value(value: Date | string | null) {
+ let _value = this._value;
+ if(value === null) {
+ this._value = null;
+ } else if(typeof value === "string") {
+ this._value = new Date(value);
} else {
- this.setValue(null);
+ this._value = value;
}
- this.initializePlugins(template);
+ let prev = _value === null ? null : new Date(_value);
+ let next = this._value === null ? null : new Date(this._value);
+ this.emit("update", next, prev);
}
-
+
+ /**
+ * Creates a new {@link DateTimeProperty}.
+ * @param params
+ * The property's parameters.
+ */
+ constructor(params: AtomicPropertyParameters);
+
+ /**
+ * Creates a new {@link DateTimeProperty}.
+ * @param params
+ * The property's parameters.
+ * @param assembler
+ * The property's assembler.
+ */
+ constructor(params: AtomicPropertyParameters, assembler?: PropertyAssembler);
+ constructor(params: AtomicPropertyParameters, assembler?: PropertyAssembler) {
+ super(params, assembler);
+ this._value = null;
+ this._plugins = null;
+ }
+
+
///////////////////////////////////////////////////////////////////////////
- /// 1. IDateTimeProperty Methods ////////////////////////////////////////
+ /// 1. Property Cloning /////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Clones the property.
+ * @returns
+ * The cloned property.
+ */
+ public override clone(): DateTimeProperty
/**
- * Sets the property's value directly.
- * @param value
- * The property's new value.
+ * Clones the property.
+ * @param assembler
+ * The cloned property's assembler.
+ * @returns
+ * The cloned property.
*/
- public setValue(value: Date | string | null): void {
- if(value === null) {
- this.value = null;
- } else if(typeof value === "string") {
- this.value = new Date(value);
- } else {
- this.value = value;
- }
+ public override clone(assembler?: PropertyAssembler): DateTimeProperty {
+ // Create property
+ let prop = new DateTimeProperty({
+ id : this.id,
+ name : this.name,
+ path : this.path,
+ link : this.link,
+ row : this.row,
+ col : this.col,
+ required : this.required,
+ alignment : this.alignment
+ }, assembler);
+ // Clone values
+ prop.value = this._value;
+ // Clone plugins
+ this._plugins?.forEach(({ plugin }) => {
+ prop.tryInstallPlugin(plugin)
+ });
+ // Return
+ return prop;
}
+
+
+ ///////////////////////////////////////////////////////////////////////////
+ /// 2. Plugin Management ////////////////////////////////////////////////
+ ///////////////////////////////////////////////////////////////////////////
+
/**
- * Creates a new command.
+ * Attempts to install a plugin into the property.
+ * @param plugin
+ * The plugin to install.
+ * @returns
+ * True if the plugin was successfully installed, false otherwise.
*/
- public newCommand(): void {
- // TODO: Implement command construct
- throw new Error("Method not implemented.");
+ public tryInstallPlugin(plugin: Plugin): boolean {
+ let result;
+ // Don't allocate manager until absolutely necessary
+ if(this._plugins === null) {
+ this._plugins = new PluginManager(this, this.root);
+ }
+ result = this._plugins.tryInstallPlugin(plugin);
+ // Deallocate manager if no plugins were installed
+ if(this._plugins.length === 0) {
+ this._plugins = null;
+ }
+ return result;
}
-
+
/**
- * Returns a string representation of the property.
+ * Attempts to install a list of plugins into the property.
+ * @param plugin
+ * The plugins to install.
* @returns
- * A string representation of the property.
+ * True if all plugins were successfully installed, false otherwise.
*/
- public override toString(): string | undefined {
- return this.value !== null ? `${ this.value }` : undefined;
+ public tryInstallPlugins(plugins: Plugin[]): boolean {
+ let result = true;
+ for(let plugin of plugins) {
+ result &&= this.tryInstallPlugin(plugin);
+ }
+ return result;
}
///////////////////////////////////////////////////////////////////////////
- /// 2. Event Methods ////////////////////////////////////////////////////
+ /// 3. toString /////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
+
/**
- * Property update behavior.
- * @param newValue
- * The property's new value.
- * @param oldValue
- * The property's old value.
+ * Returns a string representation of the property.
+ * @returns
+ * A string representation of the property.
*/
- public onUpdate(newValue: Date, oldValue: Date) {
- // TODO: Link update event
- this.emit("update", newValue, oldValue);
- this._section.onPropertyUpdate(this, newValue, oldValue);
+ public override toString(): string | undefined {
+ return this._value !== null ? `${ this._value }` : undefined;
}
}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Page/Property/DateTimeProperty/IDateTimeProperty.ts b/src/cti_authoring_tool/src/assets/scripts/Page/Property/DateTimeProperty/IDateTimeProperty.ts
deleted file mode 100644
index 57f11a7..0000000
--- a/src/cti_authoring_tool/src/assets/scripts/Page/Property/DateTimeProperty/IDateTimeProperty.ts
+++ /dev/null
@@ -1,85 +0,0 @@
-import { AtomicPropertyEvents, IAtomicProperty } from "../AtomicProperty/IAtomicProperty";
-
-export interface IDateTimeProperty extends IAtomicProperty {
-
- /**
- * The property's value.
- */
- readonly value: Date | null;
-
-
- ///////////////////////////////////////////////////////////////////////////
- // 1. Value Manipulation ////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////
-
-
- /**
- * Sets the property's value directly.
- * @param value
- * The property's new value.
- */
- setValue(value: Date | null): void;
-
- /**
- * Creates a new command.
- */
- newCommand(): void;
-
-
- ///////////////////////////////////////////////////////////////////////////
- // 2. Events ////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////
-
-
- /**
- * Adds an event listener to the property.
- * @param event
- * The event to subscribe to.
- * @param callback
- * The function to call once the event has fired.
- */
- on(event: K, callback: DateTimePropertyEvents[K]): void;
-
- /**
- * Adds an event listener to the property that will be fired once and then
- * removed.
- * @param event
- * The event to subscribe to.
- * @param callback
- * The function to call once the event has fired.
- */
- once(event: K, callback: DateTimePropertyEvents[K]): void;
-
- /**
- * Removes all event listeners associated with a given event. If no event
- * name is specified, all event listeners are removed.
- * @param event
- * The name of the event.
- */
- removeAllListeners(event?: K): void;
-
-
- ///////////////////////////////////////////////////////////////////////////
- // 3. toString //////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////
-
-
- /**
- * Returns a string representation of the property.
- * @returns
- * A string representation of the property.
- */
- toString(): string | undefined
-
-}
-
-
-///////////////////////////////////////////////////////////////////////////////
-// Internal Types ///////////////////////////////////////////////////////////
-///////////////////////////////////////////////////////////////////////////////
-
-
-// Event types
-export interface DateTimePropertyEvents extends AtomicPropertyEvents {
- "update" : (newValue: Date, oldValue: Date) => void
-}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Page/Property/DateTimeProperty/TimeProperty.ts b/src/cti_authoring_tool/src/assets/scripts/Page/Property/DateTimeProperty/TimeProperty.ts
new file mode 100644
index 0000000..35d06d2
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/Page/Property/DateTimeProperty/TimeProperty.ts
@@ -0,0 +1,68 @@
+import { DateTimeProperty } from "./DateTimeProperty";
+import { PropertyAssembler } from "../PropertyAssembler";
+import { AtomicPropertyParameters } from "../AtomicProperty/AtomicPropertyParameters";
+
+export class TimeProperty extends DateTimeProperty {
+
+ /**
+ * Creates a new {@link TimeProperty}.
+ * @param params
+ * The property's parameters.
+ */
+ constructor(params: AtomicPropertyParameters);
+
+ /**
+ * Creates a new {@link TimeProperty}.
+ * @param params
+ * The property's parameters.
+ * @param assembler
+ * The property's assembler.
+ */
+ constructor(params: AtomicPropertyParameters, assembler?: PropertyAssembler);
+ constructor(params: AtomicPropertyParameters, assembler?: PropertyAssembler) {
+ super(params, assembler);
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////
+ /// 1. Property Cloning /////////////////////////////////////////////////
+ ///////////////////////////////////////////////////////////////////////////
+
+
+ /**
+ * Clones the property.
+ * @returns
+ * The cloned property.
+ */
+ public override clone(): TimeProperty
+
+ /**
+ * Clones the property.
+ * @param assembler
+ * The cloned property's assembler.
+ * @returns
+ * The cloned property.
+ */
+ public override clone(assembler?: PropertyAssembler): TimeProperty {
+ // Create property
+ let prop = new TimeProperty({
+ id : this.id,
+ name : this.name,
+ path : this.path,
+ link : this.link,
+ row : this.row,
+ col : this.col,
+ required : this.required,
+ alignment : this.alignment
+ }, assembler);
+ // Clone values
+ prop.value = this.value;
+ // Clone plugins
+ this._plugins?.forEach(({ plugin }) => {
+ prop.tryInstallPlugin(plugin)
+ });
+ // Return
+ return prop;
+ }
+
+}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Page/Property/DateTimeProperty/index.ts b/src/cti_authoring_tool/src/assets/scripts/Page/Property/DateTimeProperty/index.ts
new file mode 100644
index 0000000..a52dc05
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/Page/Property/DateTimeProperty/index.ts
@@ -0,0 +1,3 @@
+export * from "./DateProperty";
+export * from "./TimeProperty";
+export * from "./DateTimeProperty";
diff --git a/src/cti_authoring_tool/src/assets/scripts/Page/Property/EnumProperty/EnumProperty.ts b/src/cti_authoring_tool/src/assets/scripts/Page/Property/EnumProperty/EnumProperty.ts
index f308b5f..1dc7524 100644
--- a/src/cti_authoring_tool/src/assets/scripts/Page/Property/EnumProperty/EnumProperty.ts
+++ b/src/cti_authoring_tool/src/assets/scripts/Page/Property/EnumProperty/EnumProperty.ts
@@ -1,120 +1,193 @@
-import { PageSection } from "../../PageSection";
import { AtomicProperty } from "..";
-import { IAtomicProperty } from "../AtomicProperty/IAtomicProperty";
-import { EnumPropertyTemplate } from "@/assets/scripts/AppConfiguration";
+import { PropertyAssembler } from "../PropertyAssembler";
+import { Plugin, PluginManager } from "../../Plugins";
+import { EnumPropertyParameters } from "./EnumPropertyParameters";
-export class EnumProperty extends AtomicProperty implements IAtomicProperty {
+export class EnumProperty extends AtomicProperty {
+
+ /**
+ * The property's set of options.
+ */
+ public readonly options: ReadonlyMap
/**
* The property's value.
*/
- public value: string | null;
+ private _value: string | null;
/**
- * The property's set of options.
+ * The property's plugin manager.
+ */
+ private _plugins: PluginManager | null;
+
+
+ /**
+ * The property's value.
+ */
+ public get value(): string | null {
+ return this._value;
+ }
+
+ /**
+ * The property value's setter.
*/
- public readonly options: Map
+ public set value(value: string | null) {
+ let lastValue = this._value;
+ if(value === null) {
+ this._value = null;
+ } else if(this.options.has(value)) {
+ this._value = value;
+ } else {
+ throw new Error(`Enum value '${ value }' is not a valid option.`);
+ }
+ this.emit("update", this._value, lastValue);
+ }
+
+ /**
+ * The property's enum value.
+ */
+ public get enumValue(): any {
+ return this._value === null ? null : this.options.get(this._value)!.value;
+ }
/**
* Creates a new {@link EnumProperty}.
- * @param section
- * The property's section.
- * @param template
- * The property's template.
+ * @param params
+ * The property's parameters.
*/
- constructor(section: PageSection, template: EnumPropertyTemplate);
+ constructor(params: EnumPropertyParameters);
/**
* Creates a new {@link EnumProperty}.
- * @param section
- * The property's section.
- * @param template
- * The property's template.
- * @param value
- * The property's value.
+ * @param params
+ * The property's parameters.
+ * @param assembler
+ * The property's assembler.
*/
- constructor(section: PageSection, template: EnumPropertyTemplate, value: string);
- constructor(section: PageSection, template: EnumPropertyTemplate, value?: string) {
- super(section, template);
- this.value = null;
- this.options = new Map();
+ constructor(params: EnumPropertyParameters, assembler?: PropertyAssembler);
+ constructor(params: EnumPropertyParameters, assembler?: PropertyAssembler) {
+ super(params, assembler);
// Validate options
- for(let option of template.options) {
+ let options = new Map();
+ for(let option of params.options) {
let { id, text, value } = option;
- if(!this.options.has(id)) {
- this.options.set(id, { text, value })
+ if(!options.has(id)) {
+ options.set(id, { text, value })
} else {
throw new Error("All enum ids must be unique.");
}
}
+ this.options = options;
// Set value
- if(value !== undefined) {
- this.setValue(value);
- } else if(template.default !== undefined) {
- this.setValue(template.default);
- } else {
- this.setValue(null);
- }
- this.initializePlugins(template);
+ this._value = null;
+ this._plugins = null;
}
-
+
///////////////////////////////////////////////////////////////////////////
- /// 1. INumberProperty Methods //////////////////////////////////////////
+ /// 1. Property Cloning /////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Clones the property.
+ * @returns
+ * The cloned property.
+ */
+ public override clone(): EnumProperty;
/**
- * Sets the property's value directly.
- * @param value
- * The property's new value.
+ * Clones the property.
+ * @param assembler
+ * The cloned property's assembler.
+ * @returns
+ * The cloned property.
*/
- public setValue(value: string | null): void {
- // Validate value
- if(value === null) {
- this.value = null;
- } else if(this.options.has(value)) {
- this.value = value;
- } else {
- throw new Error(`Enum value '${ value }' is not a valid option.`);
- }
+ public override clone(assembler?: PropertyAssembler): EnumProperty {
+ // Clone options
+ let options = [...this.options.entries()].map(o => ({
+ id : o[0],
+ text : o[1].text,
+ value : o[1].value
+ }));
+ // Create property
+ let prop = new EnumProperty({
+ id : this.id,
+ name : this.name,
+ path : this.path,
+ link : this.link,
+ row : this.row,
+ col : this.col,
+ required : this.required,
+ alignment : this.alignment,
+ options
+ }, assembler);
+ // Clone values
+ prop.value = this._value;
+ // Clone plugins
+ this._plugins?.forEach(({ plugin }) => {
+ prop.tryInstallPlugin(plugin)
+ });
+ // Return
+ return prop;
}
+
+ ///////////////////////////////////////////////////////////////////////////
+ /// 2. Plugin Management ////////////////////////////////////////////////
+ ///////////////////////////////////////////////////////////////////////////
+
+
/**
- * Creates a new command.
+ * Attempts to install a plugin into the property.
+ * @param plugin
+ * The plugin to install.
+ * @returns
+ * True if the plugin was successfully installed, false otherwise.
*/
- public newCommand(): void {
- // TODO: Implement command construct
- throw new Error("Method not implemented.");
+ public tryInstallPlugin(plugin: Plugin): boolean {
+ let result;
+ // Don't allocate manager until absolutely necessary
+ if(this._plugins === null) {
+ this._plugins = new PluginManager(this, this.root);
+ }
+ result = this._plugins.tryInstallPlugin(plugin);
+ // Deallocate manager if no plugins were installed
+ if(this._plugins.length === 0) {
+ this._plugins = null;
+ }
+ return result;
}
-
+
/**
- * Returns a string representation of the property.
+ * Attempts to install a list of plugins into the property.
+ * @param plugin
+ * The plugins to install.
* @returns
- * A string representation of the property.
+ * True if all plugins were successfully installed, false otherwise.
*/
- public override toString(): string | undefined {
- return this.value !== null ? this.options.get(this.value)!.text : undefined;
+ public tryInstallPlugins(plugins: Plugin[]): boolean {
+ let result = true;
+ for(let plugin of plugins) {
+ result &&= this.tryInstallPlugin(plugin);
+ }
+ return result;
}
///////////////////////////////////////////////////////////////////////////
- /// 2. Event Methods ////////////////////////////////////////////////////
+ /// 3. toString /////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
/**
- * Property update behavior.
- * @param newValue
- * The property's new value.
- * @param oldValue
- * The property's old value.
+ * Returns a string representation of the property.
+ * @returns
+ * A string representation of the property.
*/
- public onUpdate(newValue: any, oldValue: any) {
- // TODO: Link update event
- this.emit("update", newValue, oldValue);
- this._section.onPropertyUpdate(this, newValue, oldValue);
+ public override toString(): string | undefined {
+ return this._value !== null ? this.options.get(this._value)!.text : undefined;
}
}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Page/Property/EnumProperty/EnumPropertyParameters.ts b/src/cti_authoring_tool/src/assets/scripts/Page/Property/EnumProperty/EnumPropertyParameters.ts
new file mode 100644
index 0000000..053c640
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/Page/Property/EnumProperty/EnumPropertyParameters.ts
@@ -0,0 +1,11 @@
+import { AtomicPropertyParameters } from "../AtomicProperty/AtomicPropertyParameters";
+
+export interface EnumPropertyParameters extends AtomicPropertyParameters {
+
+ /**
+ * The property's set of options.
+ */
+ // TODO: `value` must be restricted to valid JSON types
+ options: { id: string, text: string, value: any }[]
+
+}
\ No newline at end of file
diff --git a/src/cti_authoring_tool/src/assets/scripts/Page/Property/EnumProperty/IEnumProperty.ts b/src/cti_authoring_tool/src/assets/scripts/Page/Property/EnumProperty/IEnumProperty.ts
deleted file mode 100644
index 28bde66..0000000
--- a/src/cti_authoring_tool/src/assets/scripts/Page/Property/EnumProperty/IEnumProperty.ts
+++ /dev/null
@@ -1,90 +0,0 @@
-import { AtomicPropertyEvents, IAtomicProperty } from "../AtomicProperty/IAtomicProperty";
-
-export interface IEnumProperty extends IAtomicProperty {
-
- /**
- * The property's value.
- */
- readonly value: string | null;
-
- /**
- * The property's set of options.
- */
- readonly options: ReadonlyMap;
-
-
- ///////////////////////////////////////////////////////////////////////////
- // 1. Value Manipulation ////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////
-
-
- /**
- * Sets the property's value directly.
- * @param value
- * The property's new value.
- */
- setValue(value: string | null): void;
-
- /**
- * Creates a new command.
- */
- newCommand(): void;
-
-
- ///////////////////////////////////////////////////////////////////////////
- // 2. Events ////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////
-
-
- /**
- * Adds an event listener to the property.
- * @param event
- * The event to subscribe to.
- * @param callback
- * The function to call once the event has fired.
- */
- on(event: K, callback: EnumPropertyEvents[K]): void;
-
- /**
- * Adds an event listener to the property that will be fired once and then
- * removed.
- * @param event
- * The event to subscribe to.
- * @param callback
- * The function to call once the event has fired.
- */
- once(event: K, callback: EnumPropertyEvents[K]): void;
-
- /**
- * Removes all event listeners associated with a given event. If no event
- * name is specified, all event listeners are removed.
- * @param event
- * The name of the event.
- */
- removeAllListeners(event?: K): void;
-
-
- ///////////////////////////////////////////////////////////////////////////
- // 3. toString //////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////
-
-
- /**
- * Returns a string representation of the property.
- * @returns
- * A string representation of the property.
- */
- toString(): string | undefined
-
-}
-
-
-///////////////////////////////////////////////////////////////////////////////
-// Internal Types ///////////////////////////////////////////////////////////
-///////////////////////////////////////////////////////////////////////////////
-
-
-// Event types
-export interface EnumPropertyEvents extends AtomicPropertyEvents {
- "update" : (newValue: any, oldValue: any) => void
-}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Page/Property/EnumProperty/index.ts b/src/cti_authoring_tool/src/assets/scripts/Page/Property/EnumProperty/index.ts
new file mode 100644
index 0000000..6edcc61
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/Page/Property/EnumProperty/index.ts
@@ -0,0 +1,2 @@
+export * from "./EnumProperty";
+export * from "./EnumPropertyParameters";
diff --git a/src/cti_authoring_tool/src/assets/scripts/Page/Property/IProperty.ts b/src/cti_authoring_tool/src/assets/scripts/Page/Property/IProperty.ts
deleted file mode 100644
index d9bc9cc..0000000
--- a/src/cti_authoring_tool/src/assets/scripts/Page/Property/IProperty.ts
+++ /dev/null
@@ -1,113 +0,0 @@
-import { PropertyType } from "../../AppConfiguration";
-
-export interface IProperty {
-
- /**
- * The property's id.
- */
- readonly id: string;
-
- /**
- * The property's name.
- */
- readonly name: string;
-
- /**
- * The property's type.
- */
- readonly type: PropertyType;
-
- /**
- * The property's row position.
- */
- readonly row: Readonly | ReadonlyArray;
-
- /**
- * The property's column position.
- */
- readonly col: Readonly | ReadonlyArray;
-
- /**
- * The property's help link.
- */
- readonly help: string | null;
-
- /**
- * The property's primary status.
- */
- readonly isPrimary: boolean;
-
-
- ///////////////////////////////////////////////////////////////////////////
- // 1. Action Registration ///////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////
-
-
- /**
- * Registers a property action.
- * @param name
- * The action's name.
- * @param action
- * The action.
- */
- registerAction(name: string, action: () => void): void;
-
-
- ///////////////////////////////////////////////////////////////////////////
- // 2. Events ////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////
-
-
- /**
- * Adds an event listener to the property.
- * @param event
- * The event to subscribe to.
- * @param callback
- * The function to call once the event has fired.
- */
- on(event: K, callback: PropertyEvents[K]): void;
-
- /**
- * Adds an event listener to the property that will be fired once and then
- * removed.
- * @param event
- * The event to subscribe to.
- * @param callback
- * The function to call once the event has fired.
- */
- once(event: K, callback: PropertyEvents[K]): void;
-
- /**
- * Removes all event listeners associated with a given event. If no event
- * name is specified, all event listeners are removed.
- * @param event
- * The name of the event.
- */
- removeAllListeners(event?: K): void;
-
-
- ///////////////////////////////////////////////////////////////////////////
- // 3. toString //////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////
-
-
- /**
- * Returns a string representation of the property.
- * @returns
- * A string representation of the property.
- */
- toString(): string | undefined;
-
-}
-
-
-///////////////////////////////////////////////////////////////////////////////
-// Internal Types ///////////////////////////////////////////////////////////
-///////////////////////////////////////////////////////////////////////////////
-
-
-// Event types
-export interface PropertyEvents {
- "mount" : (el: HTMLElement) => void,
- "destroy" : () => void
-}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Page/Property/NumberProperty/FloatProperty.ts b/src/cti_authoring_tool/src/assets/scripts/Page/Property/NumberProperty/FloatProperty.ts
new file mode 100644
index 0000000..5e04b30
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/Page/Property/NumberProperty/FloatProperty.ts
@@ -0,0 +1,93 @@
+import { clamp } from "@/assets/scripts/Utilities";
+import { AtomicProperty } from "..";
+import { NumberProperty } from "./NumberProperty";
+import { PropertyAssembler } from "../PropertyAssembler";
+import { NumberPropertyParameters } from "./NumberPropertyParameters";
+
+export class FloatProperty extends NumberProperty {
+
+ /**
+ * The property's value.
+ */
+ public override get value(): number | null {
+ return this._value;
+ }
+
+ /**
+ * The property value's setter.
+ */
+ public override set value(value: number | null) {
+ let lastValue = this._value;
+ if(value === null) {
+ this._value = value;
+ } else {
+ this._value = clamp(value, this.min, this.max);
+ }
+ this.emit("update", this._value, lastValue);
+ }
+
+
+ /**
+ * Creates a new {@link FloatProperty}.
+ * @param params
+ * The property's parameters.
+ */
+ constructor(params: NumberPropertyParameters);
+
+ /**
+ * Creates a new {@link FloatProperty}.
+ * @param params
+ * The property's parameters.
+ * @param assembler
+ * The property's assembler.
+ */
+ constructor(params: NumberPropertyParameters, assembler?: PropertyAssembler);
+ constructor(params: NumberPropertyParameters, assembler?: PropertyAssembler) {
+ super(params, assembler);
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////
+ /// 1. Property Cloning /////////////////////////////////////////////////
+ ///////////////////////////////////////////////////////////////////////////
+
+
+ /**
+ * Clones the property.
+ * @returns
+ * The cloned property.
+ */
+ public override clone(): FloatProperty
+
+ /**
+ * Clones the property.
+ * @param assembler
+ * The cloned property's assembler.
+ * @returns
+ * The cloned property.
+ */
+ public override clone(assembler?: PropertyAssembler): FloatProperty {
+ // Create property
+ let prop = new FloatProperty({
+ id : this.id,
+ name : this.name,
+ path : this.path,
+ link : this.link,
+ row : this.row,
+ col : this.col,
+ required : this.required,
+ alignment : this.alignment,
+ min : this.min,
+ max : this.max
+ }, assembler);
+ // Clone values
+ prop.value = this._value;
+ // Clone plugins
+ this._plugins?.forEach(({ plugin }) => {
+ prop.tryInstallPlugin(plugin)
+ });
+ // Return
+ return prop;
+ }
+
+}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Page/Property/NumberProperty/INumberProperty.ts b/src/cti_authoring_tool/src/assets/scripts/Page/Property/NumberProperty/INumberProperty.ts
deleted file mode 100644
index 83af73f..0000000
--- a/src/cti_authoring_tool/src/assets/scripts/Page/Property/NumberProperty/INumberProperty.ts
+++ /dev/null
@@ -1,95 +0,0 @@
-import { AtomicPropertyEvents, IAtomicProperty } from "../AtomicProperty/IAtomicProperty";
-
-export interface INumberProperty extends IAtomicProperty {
-
- /**
- * The property's value.
- */
- readonly value: null | number;
-
- /**
- * The property's minimum allowed value.
- */
- readonly min: number;
-
- /**
- * The property's maximum allowed value.
- */
- readonly max: number;
-
-
- ///////////////////////////////////////////////////////////////////////////
- // 1. Value Manipulation ////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////
-
-
- /**
- * Sets the property's value directly.
- * @param value
- * The property's new value.
- */
- setValue(value: number | null): void;
-
- /**
- * Creates a new command.
- */
- newCommand(): void;
-
-
- ///////////////////////////////////////////////////////////////////////////
- // 2. Events ////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////
-
-
- /**
- * Adds an event listener to the property.
- * @param event
- * The event to subscribe to.
- * @param callback
- * The function to call once the event has fired.
- */
- on(event: K, callback: NumberPropertyEvents[K]): void;
-
- /**
- * Adds an event listener to the property that will be fired once and then
- * removed.
- * @param event
- * The event to subscribe to.
- * @param callback
- * The function to call once the event has fired.
- */
- once(event: K, callback: NumberPropertyEvents[K]): void;
-
- /**
- * Removes all event listeners associated with a given event. If no event
- * name is specified, all event listeners are removed.
- * @param event
- * The name of the event.
- */
- removeAllListeners(event?: K): void;
-
-
- ///////////////////////////////////////////////////////////////////////////
- // 3. toString //////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////
-
-
- /**
- * Returns a string representation of the property.
- * @returns
- * A string representation of the property.
- */
- toString(): string | undefined
-
-}
-
-
-///////////////////////////////////////////////////////////////////////////////
-// Internal Types ///////////////////////////////////////////////////////////
-///////////////////////////////////////////////////////////////////////////////
-
-
-// Event types
-export interface NumberPropertyEvents extends AtomicPropertyEvents {
- "update" : (oldValue: number, newValue: number) => void
-}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Page/Property/NumberProperty/IntegerProperty.ts b/src/cti_authoring_tool/src/assets/scripts/Page/Property/NumberProperty/IntegerProperty.ts
new file mode 100644
index 0000000..640febd
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/Page/Property/NumberProperty/IntegerProperty.ts
@@ -0,0 +1,93 @@
+import { clamp } from "@/assets/scripts/Utilities";
+import { AtomicProperty } from "..";
+import { NumberProperty } from "./NumberProperty";
+import { PropertyAssembler } from "../PropertyAssembler";
+import { NumberPropertyParameters } from "./NumberPropertyParameters";
+
+export class IntegerProperty extends NumberProperty {
+
+ /**
+ * The property's value.
+ */
+ public override get value(): number | null {
+ return this._value;
+ }
+
+ /**
+ * The property value's setter.
+ */
+ public override set value(value: number | null) {
+ let lastValue = this.value;
+ if(value === null) {
+ this._value = value;
+ } else {
+ this._value = Math.round(clamp(value, this.min, this.max));
+ }
+ this.emit("update", this.value, lastValue);
+ }
+
+
+ /**
+ * Creates a new {@link IntegerProperty}.
+ * @param params
+ * The property's parameters.
+ */
+ constructor(params: NumberPropertyParameters);
+
+ /**
+ * Creates a new {@link IntegerProperty}.
+ * @param params
+ * The property's parameters.
+ * @param assembler
+ * The property's assembler.
+ */
+ constructor(params: NumberPropertyParameters, assembler?: PropertyAssembler);
+ constructor(params: NumberPropertyParameters, assembler?: PropertyAssembler) {
+ super(params, assembler);
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////
+ /// 1. Property Cloning /////////////////////////////////////////////////
+ ///////////////////////////////////////////////////////////////////////////
+
+
+ /**
+ * Clones the property.
+ * @returns
+ * The cloned property.
+ */
+ public override clone(): IntegerProperty
+
+ /**
+ * Clones the property.
+ * @param assembler
+ * The cloned property's assembler.
+ * @returns
+ * The cloned property.
+ */
+ public override clone(assembler?: PropertyAssembler): IntegerProperty {
+ // Create property
+ let prop = new IntegerProperty({
+ id : this.id,
+ name : this.name,
+ path : this.path,
+ link : this.link,
+ row : this.row,
+ col : this.col,
+ required : this.required,
+ alignment : this.alignment,
+ min : this.min,
+ max : this.max
+ }, assembler);
+ // Clone values
+ prop.value = this.value;
+ // Clone plugins
+ this._plugins?.forEach(({ plugin }) => {
+ prop.tryInstallPlugin(plugin)
+ });
+ // Return
+ return prop;
+ }
+
+}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Page/Property/NumberProperty/NumberProperty.ts b/src/cti_authoring_tool/src/assets/scripts/Page/Property/NumberProperty/NumberProperty.ts
index 949f3f6..6dcecb3 100644
--- a/src/cti_authoring_tool/src/assets/scripts/Page/Property/NumberProperty/NumberProperty.ts
+++ b/src/cti_authoring_tool/src/assets/scripts/Page/Property/NumberProperty/NumberProperty.ts
@@ -1,15 +1,9 @@
-import { clamp } from "@/assets/scripts/Utilities";
-import { PageSection } from "../../PageSection";
import { AtomicProperty } from "..";
-import { INumberProperty } from "./INumberProperty";
-import { NumberPropertyTemplate, PropertyType } from "../../../AppConfiguration";
+import { PropertyAssembler } from "../PropertyAssembler";
+import { Plugin, PluginManager } from "../../Plugins";
+import { NumberPropertyParameters } from "./NumberPropertyParameters";
-export class NumberProperty extends AtomicProperty implements INumberProperty {
-
- /**
- * The property's value.
- */
- public value: number | null;
+export abstract class NumberProperty extends AtomicProperty {
/**
* The property's minimum allowed value.
@@ -21,100 +15,106 @@ export class NumberProperty extends AtomicProperty implements INumberProperty {
*/
public readonly max: number;
+ /**
+ * The property's value.
+ */
+ protected _value: number | null;
+
+ /**
+ * The property's plugin manager.
+ */
+ protected _plugins: PluginManager | null;
+
+
+ /**
+ * The property's value.
+ */
+ public abstract get value(): number | null;
+
+ /**
+ * The property value's setter.
+ */
+ public abstract set value(value: number | null);
+
/**
* Creates a new {@link NumberProperty}.
- * @param section
- * The property's section.
- * @param template
- * The property's template.
+ * @param params
+ * The property's parameters.
*/
- constructor(section: PageSection, template: NumberPropertyTemplate);
+ constructor(params: NumberPropertyParameters);
/**
* Creates a new {@link NumberProperty}.
- * @param section
- * The property's section.
- * @param template
- * The property's template.
- * @param value
- * The property's value.
+ * @param params
+ * The property's parameters.
+ * @param assembler
+ * The property's assembler.
*/
- constructor(section: PageSection, template: NumberPropertyTemplate, value: number);
- constructor(section: PageSection, template: NumberPropertyTemplate, value?: number) {
- super(section, template);
- this.value = null;
- this.min = template.min ?? -Infinity;
- this.max = template.max ?? Infinity;
- if(value !== undefined) {
- this.setValue(value);
- } else if(template.default !== undefined) {
- this.setValue(template.default);
- } else {
- this.setValue(null);
- }
- this.initializePlugins(template);
+ constructor(params: NumberPropertyParameters, assembler?: PropertyAssembler);
+ constructor(params: NumberPropertyParameters, assembler?: PropertyAssembler) {
+ super(params, assembler);
+ this.min = params.min ?? -Infinity;
+ this.max = params.max ?? Infinity;
+ this._value = null;
+ this._plugins = null;
}
+
///////////////////////////////////////////////////////////////////////////
- /// 1. INumberProperty Methods //////////////////////////////////////////
+ /// 1. Plugin Management ////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
/**
- * Sets the property's value directly.
- * @param value
- * The property's new value.
+ * Attempts to install a plugin into the property.
+ * @param plugin
+ * The plugin to install.
+ * @returns
+ * True if the plugin was successfully installed, false otherwise.
*/
- public setValue(value: number | null): void {
- // If null value
- if(value === null) {
- this.value = value;
- return;
+ public tryInstallPlugin(plugin: Plugin): boolean {
+ let result;
+ // Don't allocate manager until absolutely necessary
+ if(this._plugins === null) {
+ this._plugins = new PluginManager(this, this.root);
}
- // If numeric value
- let v = clamp(value, this.min, this.max);
- if(this.type === PropertyType.Integer) {
- this.value = Math.round(v);
- } else {
- this.value = v;
+ result = this._plugins.tryInstallPlugin(plugin);
+ // Deallocate manager if no plugins were installed
+ if(this._plugins.length === 0) {
+ this._plugins = null;
}
+ return result;
}
/**
- * Creates a new command.
- */
- public newCommand(): void {
- // TODO: Implement command construct
- throw new Error("Method not implemented.");
- }
-
- /**
- * Returns a string representation of the property.
+ * Attempts to install a list of plugins into the property.
+ * @param plugin
+ * The plugins to install.
* @returns
- * A string representation of the property.
+ * True if all plugins were successfully installed, false otherwise.
*/
- public override toString(): string | undefined {
- return this.value !== null ? `${ this.value }` : undefined;
+ public tryInstallPlugins(plugins: Plugin[]): boolean {
+ let result = true;
+ for(let plugin of plugins) {
+ result &&= this.tryInstallPlugin(plugin);
+ }
+ return result;
}
///////////////////////////////////////////////////////////////////////////
- /// 2. Event Methods ////////////////////////////////////////////////////
+ /// 2. toString /////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
/**
- * Property update behavior.
- * @param newValue
- * The property's new value.
- * @param oldValue
- * The property's old value.
+ * Returns a string representation of the property.
+ * @returns
+ * A string representation of the property.
*/
- public onUpdate(newValue: number, oldValue: number) {
- // TODO: Link update event
- this.emit("update", newValue, oldValue);
- this._section.onPropertyUpdate(this, newValue, oldValue);
+ public override toString(): string | undefined {
+ return this.value !== null ? `${ this.value }` : undefined;
}
}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Page/Property/NumberProperty/NumberPropertyParameters.ts b/src/cti_authoring_tool/src/assets/scripts/Page/Property/NumberProperty/NumberPropertyParameters.ts
new file mode 100644
index 0000000..d65f63e
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/Page/Property/NumberProperty/NumberPropertyParameters.ts
@@ -0,0 +1,15 @@
+import { AtomicPropertyParameters } from "../AtomicProperty/AtomicPropertyParameters";
+
+export interface NumberPropertyParameters extends AtomicPropertyParameters {
+
+ /**
+ * The property's minimum allowed value.
+ */
+ min?: number | null;
+
+ /**
+ * The property's maximum allowed value.
+ */
+ max?: number | null;
+
+}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Page/Property/NumberProperty/index.ts b/src/cti_authoring_tool/src/assets/scripts/Page/Property/NumberProperty/index.ts
new file mode 100644
index 0000000..ac29a64
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/Page/Property/NumberProperty/index.ts
@@ -0,0 +1,4 @@
+export * from "./FloatProperty";
+export * from "./IntegerProperty";
+export * from "./NumberProperty";
+export * from "./NumberPropertyParameters";
\ No newline at end of file
diff --git a/src/cti_authoring_tool/src/assets/scripts/Page/Property/Property.ts b/src/cti_authoring_tool/src/assets/scripts/Page/Property/Property.ts
index 4535528..3b0f4f8 100644
--- a/src/cti_authoring_tool/src/assets/scripts/Page/Property/Property.ts
+++ b/src/cti_authoring_tool/src/assets/scripts/Page/Property/Property.ts
@@ -1,10 +1,10 @@
-import { IProperty } from "./IProperty";
-import { PageSection } from "../PageSection";
-import { EventEmitter, String } from "../../Utilities";
-import { PagePropertyTemplate, Plugin, PropertyTemplate, PropertyType } from "../../AppConfiguration";
-import { DateTimeProperty, EnumProperty, NumberProperty, StringProperty, BasicTableProperty, ComplexTableProperty } from "./";
+import { Section } from "../Section/Section";
+import { PageElement } from "../PageElement";
+import { PropertyAssembler } from "./PropertyAssembler";
+import { PropertyParameters } from "./PropertyParameters";
+import { PropertyAction, PropertyActionText } from "./PropertyAction";
-export abstract class Property extends EventEmitter implements IProperty {
+export abstract class Property extends PageElement {
/**
* The property's id.
@@ -17,240 +17,176 @@ export abstract class Property extends EventEmitter implements IProperty {
public readonly name: string;
/**
- * The property's type.
+ * The property's export path.
*/
- public readonly type: PropertyType;
-
- /**
- * The property's row.
- */
- public readonly row: number | [number, number];
-
- /**
- * The property's column.
- */
- public readonly col: number | [number, number];
+ public readonly path: string;
/**
* The property's help link.
*/
- public readonly help: string | null;
+ public readonly link: string | null;
/**
- * The property's primary status.
+ * The property's row.
*/
- public readonly isPrimary: boolean;
+ public readonly row: number | [number, number];
/**
- * The property's plugins.
+ * The property's column.
*/
- protected _plugins: Object[];
+ public readonly col: number | [number, number];
/**
* The property's actions
*/
- protected _actions: any[];
+ protected _actions: Map | null;
+
/**
- * The property's section.
+ * The property's actions.
*/
- protected _section: PageSection;
+ public get actions(): ReadonlyMap | null {
+ return this._actions;
+ }
/**
* Creates a new {@link Property}.
- * @param section
- * The property's section.
- * @param template
- * The property's template.
+ * @param params
+ * The property's parameters.
*/
- constructor(section: PageSection, template: PropertyTemplate) {
- super();
- this._section = section;
- this.id = template.id ?? String.formatId(template.name);
- this.name = template.name;
- this.type = template.type;
- this.row = template.row;
- this.col = template.col;
- this.help = template.help ?? null;
- this.isPrimary = template.is_primary ?? false;
- this._plugins = [];
- this._actions = [];
- }
-
+ constructor(params: PropertyParameters);
+
/**
- * Returns the instance id of the page the property belongs to.
- * @returns
- * The instance id of the page the property belongs to.
+ * Creates a new {@link Property}.
+ * @param params
+ * The property's parameters.
+ * @param assembler
+ * The property's assembler.
*/
- public getPageInstance(): string {
- return this._section.getPageInstance();
+ constructor(params: PropertyParameters, assembler?: PropertyAssembler);
+ constructor(params: PropertyParameters, assembler?: PropertyAssembler) {
+ super();
+ // Configure state
+ this.id = params.id;
+ this.path = params.path ?? params.id;
+ this.name = params.name;
+ this.link = params.link ?? null;
+ this.row = params.row;
+ this.col = params.col;
+ this._parent = null;
+ this._actions = null;
+ // Configure assembler
+ if(assembler) {
+ this.__prepareAssembler(assembler);
+ }
}
///////////////////////////////////////////////////////////////////////////
- /// 1. IProperty Methods ////////////////////////////////////////////////
+ /// 1. Action Management ////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
/**
* Registers a property action.
+ * @param id
+ * The action's id.
* @param name
- * The action's name.
- * @param action
+ * The action's text.
+ * @param func
* The action.
*/
- public registerAction(name: string, action: () => void): void {
- // TODO: Implement action registration
- throw new Error("Method not implemented.");
- }
-
- /**
- * Adds an event listener to the property.
- * @param event
- * The event to subscribe to.
- * @param callback
- * The function to call once the event has fired.
- */
- public override on(event: string, callback: () => void): void {
- super.on(event, callback);
- }
-
- /**
- * Adds an event listener to the property that will be fired once and then
- * removed.
- * @param event
- * The event to subscribe to.
- * @param callback
- * The function to call once the event has fired.
- */
- public override once(event: string, callback: () => void): void {
- super.on(event, callback);
+ public registerAction(id: string, text: string, func: () => void): void {
+ // Don't allocate Map until absolutely necessary
+ if(this._actions === null) {
+ this._actions = new Map();
+ }
+ this._actions.set(id, { text, function: func });
}
/**
- * Removes all event listeners associated with a given event. If no event
- * name is specified, all event listeners are removed.
- * @param event
- * The name of the event.
+ * Invokes a property action.
+ * @param id
+ * The action's id.
*/
- public override removeAllListeners(event?: string): void {
- super.removeAllListeners(event);
+ public invokeAction(id: string) {
+ if(this._actions === null || !this._actions.has(id)) {
+ throw new Error(`'${ id }' is not a registered action.`);
+ } else {
+ this._actions.get(id)!.function();
+ }
}
- /**
- * Returns a string representation of the property.
- * @returns
- * A string representation of the property.
- */
- public abstract override toString(): string | undefined;
-
///////////////////////////////////////////////////////////////////////////
- /// 2. Event Methods ////////////////////////////////////////////////////
+ /// 2. Property Cloning /////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
/**
- * Property mount behavior.
- * @param el
- * The property's HTML container.
+ * Clones the property.
+ * @returns
+ * The cloned property.
*/
- public onMount(el: HTMLElement) {
- super.emit("mount", el);
- }
+ public abstract override clone(): Property;
/**
- * Property destroy behavior.
+ * Clones the property.
+ * @param assembler
+ * The cloned property's assembler.
+ * @returns
+ * The cloned property.
*/
- public onDestroy() {
- super.emit("destroy");
- }
+ public abstract override clone(assembler?: PropertyAssembler): Property;
///////////////////////////////////////////////////////////////////////////
- /// 3. Plugins //////////////////////////////////////////////////////////
+ /// 3. toString /////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
-
- /**
- * Initializes all plugins from a property's template.
- * @param template
- * The property's template.
- */
- protected initializePlugins(template: PropertyTemplate) {
- if(!template.plugins) {
- return;
- }
- for(let plugin of template.plugins) {
- this.tryRegisterPlugin(plugin);
- }
- }
/**
- * Attempts to register a plugin with the property.
- * @param plugin
- * The plugin to register.
+ * Returns a string representation of the property.
* @returns
- * True if the plugin was successfully registered, false otherwise.
+ * A string representation of the property.
*/
- private tryRegisterPlugin(plugin: Plugin): boolean {
- // Ensure plugin is not already registered
- if(this._plugins.find(o => o.constructor === plugin.plugin)) {
- let name = plugin.plugin.name;
- throw new Error(`Plugin '${ name }' is already registered.`);
- }
- // Register plugin
- let p;
- try {
- if(plugin.options) {
- p = new plugin.plugin(this, plugin.options());
- } else {
- p = new plugin.plugin(this);
- }
- } catch(err) {
- let name = plugin.plugin.name;
- console.error(`Failed to initialize plugin '${ name }':`);
- console.error(err);
- return false;
- }
- this._plugins.push(p);
- return true;
- }
+ public abstract override toString(): string | undefined;
///////////////////////////////////////////////////////////////////////////
- /// 4. Create Property Method ///////////////////////////////////////////
+ /// 4. Assembler Preparation ////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
-
+
/**
- * Creates a new {@link Property}.
- * @param section
- * The property's section.
- * @param template
- * The property's template.
- * @param value
- * The property's value.
+ * Prepares an assembler for the property.
+ * @returns
+ * The property's assembler.
+ * @remarks
+ * Page API use only. Do not use.
+ * @internal
*/
- public static create(section: PageSection, template: PagePropertyTemplate, value?: any): Property {
- switch(template.type) {
- case PropertyType.String:
- return new StringProperty(section, template, value);
- case PropertyType.Integer:
- case PropertyType.Float:
- return new NumberProperty(section, template, value);
- case PropertyType.Date:
- case PropertyType.Time:
- case PropertyType.DateTime:
- return new DateTimeProperty(section, template, value);
- case PropertyType.Enum:
- return new EnumProperty(section, template, value);
- case PropertyType.BasicTable:
- return new BasicTableProperty(section, template, value);
- case PropertyType.ComplexTable:
- return new ComplexTableProperty(section, template, value);
- }
+ public __prepareAssembler(): PropertyAssembler
+
+ /**
+ * Prepares an assembler for the property.
+ * @param assembler
+ * The assembler to use.
+ * @returns
+ * The property's assembler.
+ * @remarks
+ * Page API use only. Do not use.
+ * @internal
+ */
+ public __prepareAssembler(assembler?: PropertyAssembler): PropertyAssembler;
+ public __prepareAssembler(assembler: PropertyAssembler = new PropertyAssembler()): PropertyAssembler {
+ assembler.__injectAccessor({
+ property: this,
+ getParent: () => this._parent,
+ setParent: (p: Section | Property | null) => this._parent = p
+ });
+ return assembler;
}
}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Page/Property/PropertyAccessor.ts b/src/cti_authoring_tool/src/assets/scripts/Page/Property/PropertyAccessor.ts
new file mode 100644
index 0000000..47ac7a7
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/Page/Property/PropertyAccessor.ts
@@ -0,0 +1,26 @@
+import { Section } from "../Section";
+import { Property } from ".";
+import { PageElement } from "../PageElement";
+
+export interface PropertyAccessor {
+
+ /**
+ * The property.
+ */
+ property: Property;
+
+ /**
+ * Gets the property's parent.
+ * @returns
+ * The property's parent.
+ */
+ getParent: () => PageElement | null;
+
+ /**
+ * Sets the property's parent.
+ * @param p
+ * The property's parent.
+ */
+ setParent: (p: Section | Property | null) => void;
+
+}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Page/Property/PropertyAction.ts b/src/cti_authoring_tool/src/assets/scripts/Page/Property/PropertyAction.ts
new file mode 100644
index 0000000..4ac6aa4
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/Page/Property/PropertyAction.ts
@@ -0,0 +1,17 @@
+export interface PropertyActionText {
+
+ /**
+ * The action's text.
+ */
+ text: string
+
+}
+
+export interface PropertyAction extends PropertyActionText {
+
+ /**
+ * The action.
+ */
+ function: () => void
+
+}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Page/Property/PropertyAssembler.ts b/src/cti_authoring_tool/src/assets/scripts/Page/Property/PropertyAssembler.ts
new file mode 100644
index 0000000..d0e5493
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/Page/Property/PropertyAssembler.ts
@@ -0,0 +1,160 @@
+import { PropertyAccessor } from "./PropertyAccessor";
+import { SectionAssembler } from "../Section/SectionAssembler";
+import { Property, TabularPropertyAssembler } from ".";
+
+export class PropertyAssembler {
+
+ /**
+ * The property's accessor.
+ */
+ private _accessor: PropertyAccessor | null;
+
+ /**
+ * The assembler's parent.
+ */
+ private _parentAssembler: SectionAssembler | TabularPropertyAssembler | null;
+
+
+ /**
+ * The assembler's property.
+ */
+ public get property(): Property {
+ return this.accessor.property;
+ }
+
+ /**
+ * The assembler's parent.
+ */
+ public get parent(): SectionAssembler | TabularPropertyAssembler | null {
+ return this._parentAssembler;
+ }
+
+ /**
+ * The property's accessor.
+ */
+ private get accessor(): PropertyAccessor {
+ if(this._accessor === null) {
+ throw new Error("Assembler is not configured with a property.");
+ }
+ return this._accessor;
+ }
+
+
+ /**
+ * Creates a new {@link PropertyAssembler}.
+ */
+ constructor() {
+ this._accessor = null;
+ this._parentAssembler = null;
+ }
+
+
+ /**
+ * Injects a property's private resources into the assembler.
+ * @param accessor
+ * The property's accessor.
+ * @remarks
+ * Page API use only. Do not use.
+ * @internal
+ */
+ public __injectAccessor(accessor: PropertyAccessor) {
+ this._accessor = accessor;
+ }
+
+ /**
+ * Adds the property to a section.
+ * @param asm
+ * The section's assembler.
+ */
+ public attachToSection(asm: SectionAssembler) {
+ // Validate
+ if(this.belongsToParent(asm)) {
+ return;
+ }
+ // Detach existing parent, if needed
+ if(this.belongsToParent()) {
+ this.detachFromParent();
+ }
+ // Attach parent
+ this.accessor.setParent(asm.section);
+ this._parentAssembler = asm;
+ // Attach property
+ asm.attachProperty(this);
+ }
+
+ /**
+ * Adds the property to a tabular property.
+ * @param asm
+ * The tabular property's assembler.
+ * @remarks
+ * This function is designed to support `TabularProperty` (a property
+ * which contains subproperties). Because the assembler has no control
+ * over a property's children, {@link detachFromParent} must be invoked
+ * with caution. It can only disconnect a subproperty's upward
+ * relationship to its parent, not its downward one. This function will be
+ * removed or heavily refactored in the future.
+ */
+ public attachToTabularProperty(asm: TabularPropertyAssembler) {
+ // Validate
+ if(this.belongsToParent(asm)) {
+ return;
+ }
+ // Detach existing parent, if needed
+ if(this.belongsToParent()) {
+ this.detachFromParent();
+ }
+ // Attach parent
+ this.accessor.setParent(asm.property);
+ this._parentAssembler = asm;
+ }
+
+ /**
+ * Removes the property from its current parent.
+ */
+ public detachFromParent() {
+ // Validate
+ if(!this.belongsToParent()) {
+ return;
+ }
+ let parent = this._parentAssembler;
+ // Detach parent
+ this.accessor.setParent(null);
+ this._parentAssembler = null;
+ // Detach property, if needed
+ if(parent instanceof SectionAssembler) {
+ parent.detachProperty(this);
+ }
+ }
+
+ /**
+ * Tests if the property belongs to a parent.
+ * @returns
+ * True if the property belongs to a parent, false otherwise.
+ */
+ public belongsToParent(): boolean;
+
+ /**
+ * Tests if the property belongs to the given parent.
+ * @param asm
+ * The parent's assembler.
+ * @returns
+ * True if the property belongs to the given parent, false otherwise.
+ */
+ public belongsToParent(asm: SectionAssembler | TabularPropertyAssembler): boolean;
+ public belongsToParent(asm?: SectionAssembler | TabularPropertyAssembler): boolean {
+ let parent = this.accessor.getParent();
+ if(parent === null) {
+ return false;
+ } else if(asm === undefined) {
+ return true;
+ }
+ let instance;
+ if(asm instanceof SectionAssembler) {
+ instance = asm.section.instance;
+ } else {
+ instance === asm.property.instance;
+ }
+ return parent.instance === instance;
+ }
+
+}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Page/Property/PropertyParameters.ts b/src/cti_authoring_tool/src/assets/scripts/Page/Property/PropertyParameters.ts
new file mode 100644
index 0000000..c1a7724
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/Page/Property/PropertyParameters.ts
@@ -0,0 +1,33 @@
+export type PropertyParameters = {
+
+ /**
+ * The property's id.
+ */
+ id: string;
+
+ /**
+ * The property's name.
+ */
+ name: string;
+
+ /**
+ * The property's export path.
+ */
+ path?: string | null;
+
+ /**
+ * The property's help link.
+ */
+ link?: string | null;
+
+ /**
+ * The property's row.
+ */
+ row: number | [number, number];
+
+ /**
+ * The property's column.
+ */
+ col: number | [number, number];
+
+}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Page/Property/StringProperty/IStringProperty.ts b/src/cti_authoring_tool/src/assets/scripts/Page/Property/StringProperty/IStringProperty.ts
deleted file mode 100644
index 3910b6e..0000000
--- a/src/cti_authoring_tool/src/assets/scripts/Page/Property/StringProperty/IStringProperty.ts
+++ /dev/null
@@ -1,90 +0,0 @@
-import { AtomicPropertyEvents, IAtomicProperty } from "../AtomicProperty/IAtomicProperty";
-
-export interface IStringProperty extends IAtomicProperty {
-
- /**
- * The property's value.
- */
- readonly value: string | null;
-
- /**
- * The property's string suggestions.
- */
- readonly suggestions: ReadonlyArray;
-
-
- ///////////////////////////////////////////////////////////////////////////
- // 1. Value Manipulation ////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////
-
-
- /**
- * Sets the property's value directly.
- * @param value
- * The property's new value.
- */
- setValue(value: string | null): void;
-
- /**
- * Creates a new command.
- */
- newCommand(): void;
-
-
- ///////////////////////////////////////////////////////////////////////////
- // 2. Events ////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////
-
-
- /**
- * Adds an event listener to the property.
- * @param event
- * The event to subscribe to.
- * @param callback
- * The function to call once the event has fired.
- */
- on(event: K, callback: StringPropertyEvents[K]): void;
-
- /**
- * Adds an event listener to the property that will be fired once and then
- * removed.
- * @param event
- * The event to subscribe to.
- * @param callback
- * The function to call once the event has fired.
- */
- once(event: K, callback: StringPropertyEvents[K]): void;
-
- /**
- * Removes all event listeners associated with a given event. If no event
- * name is specified, all event listeners are removed.
- * @param event
- * The name of the event.
- */
- removeAllListeners(event?: K): void;
-
-
- ///////////////////////////////////////////////////////////////////////////
- // 3. toString //////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////
-
-
- /**
- * Returns a string representation of the property.
- * @returns
- * A string representation of the property.
- */
- toString(): string | undefined
-
-}
-
-
-///////////////////////////////////////////////////////////////////////////////
-// Internal Types ///////////////////////////////////////////////////////////
-///////////////////////////////////////////////////////////////////////////////
-
-
-// Event types
-export interface StringPropertyEvents extends AtomicPropertyEvents {
- "update" : (newValue: string, oldValue: string) => void
-}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Page/Property/StringProperty/StringProperty.ts b/src/cti_authoring_tool/src/assets/scripts/Page/Property/StringProperty/StringProperty.ts
index b04dc28..be1b9d7 100644
--- a/src/cti_authoring_tool/src/assets/scripts/Page/Property/StringProperty/StringProperty.ts
+++ b/src/cti_authoring_tool/src/assets/scripts/Page/Property/StringProperty/StringProperty.ts
@@ -1,103 +1,163 @@
-import { PageSection } from "../../PageSection";
import { AtomicProperty } from "..";
-import { IStringProperty } from "./IStringProperty";
-import { StringPropertyTemplate } from "../../../AppConfiguration";
+import { PropertyAssembler } from "../PropertyAssembler";
+import { Plugin, PluginManager } from "../../Plugins";
+import { AtomicPropertyParameters } from "../AtomicProperty/AtomicPropertyParameters";
-export class StringProperty extends AtomicProperty implements IStringProperty {
+export class StringProperty extends AtomicProperty {
+
+ /**
+ * The property's string suggestions.
+ */
+ public suggestions: string[];
/**
* The property's value.
*/
- public value: string | null;
+ private _value: string | null;
/**
- * The property's string suggestions.
+ * The property's plugin manager.
*/
- public suggestions: string[];
+ private _plugins: PluginManager | null;
+
+
+ /**
+ * The property's value.
+ */
+ public get value(): string | null {
+ return this._value;
+ }
+ /**
+ * The property value's setter.
+ */
+ public set value(value: string | null) {
+ let lastValue = this._value;
+ this._value = value;
+ this.emit("update", this._value, lastValue);
+ }
+
/**
* Creates a new {@link StringProperty}.
- * @param section
- * The property's section.
- * @param template
- * The property's template.
+ * @param params
+ * The property's parameters.
*/
- constructor(section: PageSection, template: StringPropertyTemplate);
+ constructor(params: AtomicPropertyParameters);
/**
* Creates a new {@link StringProperty}.
- * @param section
- * The property's section.
- * @param template
- * The property's template.
- * @param value
- * The property's value.
+ * @param params
+ * The property's parameters.
+ * @param assembler
+ * The property's assembler.
*/
- constructor(section: PageSection, template: StringPropertyTemplate, value: string);
- constructor(section: PageSection, template: StringPropertyTemplate, value?: string) {
- super(section, template);
- this.value = null;
- this.suggestions = template.suggestions ?? [];
- if(value !== undefined) {
- this.setValue(value);
- } else if(template.default !== undefined) {
- this.setValue(template.default);
- } else {
- this.setValue(null);
- }
- this.initializePlugins(template);
+ constructor(params: AtomicPropertyParameters, assembler?: PropertyAssembler);
+ constructor(params: AtomicPropertyParameters, assembler?: PropertyAssembler) {
+ super(params, assembler);
+ this.suggestions = [];
+ this._value = null;
+ this._plugins = null;
}
///////////////////////////////////////////////////////////////////////////
- /// 1. IStringProperty Methods //////////////////////////////////////////
+ /// 1. Property Cloning /////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
/**
- * Sets the property's value directly.
- * @param value
- * The property's new value.
+ * Clones the property.
+ * @returns
+ * The cloned property.
+ */
+ public override clone(): StringProperty
+
+ /**
+ * Clones the property.
+ * @param assembler
+ * The cloned property's assembler.
+ * @returns
+ * The cloned property.
*/
- public setValue(value: string | null): void {
- this.value = value;
+ public override clone(assembler?: PropertyAssembler): StringProperty {
+ // Create property
+ let prop = new StringProperty({
+ id : this.id,
+ name : this.name,
+ path : this.path,
+ link : this.link,
+ row : this.row,
+ col : this.col,
+ required : this.required,
+ alignment : this.alignment
+ }, assembler);
+ // Clone values
+ prop.value = this._value;
+ prop.suggestions = [...this.suggestions];
+ // Clone plugins
+ this._plugins?.forEach(({ plugin }) => {
+ prop.tryInstallPlugin(plugin);
+ });
+ // Return
+ return prop;
}
+
+ ///////////////////////////////////////////////////////////////////////////
+ /// 2. Plugin Management ////////////////////////////////////////////////
+ ///////////////////////////////////////////////////////////////////////////
+
+
/**
- * Creates a new command.
+ * Attempts to install a plugin into the property.
+ * @param plugin
+ * The plugin to install.
+ * @returns
+ * True if the plugin was successfully installed, false otherwise.
*/
- public newCommand(): void {
- // TODO: Implement command construct
- throw new Error("Method not implemented.");
+ public tryInstallPlugin(plugin: Plugin): boolean {
+ let result;
+ // Don't allocate manager until absolutely necessary
+ if(this._plugins === null) {
+ this._plugins = new PluginManager(this, this.root);
+ }
+ result = this._plugins.tryInstallPlugin(plugin);
+ // Deallocate manager if no plugins were installed
+ if(this._plugins.length === 0) {
+ this._plugins = null;
+ }
+ return result;
}
/**
- * Returns a string representation of the property.
+ * Attempts to install a list of plugins into the property.
+ * @param plugin
+ * The plugins to install.
* @returns
- * A string representation of the property.
+ * True if all plugins were successfully installed, false otherwise.
*/
- public override toString(): string | undefined {
- return this.value ?? undefined;
+ public tryInstallPlugins(plugins: Plugin[]): boolean {
+ let result = true;
+ for(let plugin of plugins) {
+ result &&= this.tryInstallPlugin(plugin);
+ }
+ return result;
}
///////////////////////////////////////////////////////////////////////////
- /// 2. Event Methods ////////////////////////////////////////////////////
+ /// 3. toString /////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
/**
- * Property update behavior.
- * @param newValue
- * The property's new value.
- * @param oldValue
- * The property's old value.
+ * Returns a string representation of the property.
+ * @returns
+ * A string representation of the property.
*/
- public onUpdate(newValue: string, oldValue: string) {
- // TODO: Link update event
- this.emit("update", newValue, oldValue);
- this._section.onPropertyUpdate(this, newValue, oldValue);
+ public override toString(): string | undefined {
+ return this._value ?? undefined;
}
}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Page/Property/StringProperty/index.ts b/src/cti_authoring_tool/src/assets/scripts/Page/Property/StringProperty/index.ts
new file mode 100644
index 0000000..2e43b9a
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/Page/Property/StringProperty/index.ts
@@ -0,0 +1 @@
+export * from "./StringProperty";
diff --git a/src/cti_authoring_tool/src/assets/scripts/Page/Property/TabularProperty/ITabularProperty.ts b/src/cti_authoring_tool/src/assets/scripts/Page/Property/TabularProperty/ITabularProperty.ts
deleted file mode 100644
index 00aa93f..0000000
--- a/src/cti_authoring_tool/src/assets/scripts/Page/Property/TabularProperty/ITabularProperty.ts
+++ /dev/null
@@ -1,201 +0,0 @@
-import { Sort } from "./Sort";
-import { ColumnSnapshot } from "./ColumnSnapshot";
-import { IAtomicProperty } from "../AtomicProperty/IAtomicProperty";
-import { TablePropertyState } from "./TablePropertyState";
-import { IProperty, PropertyEvents } from "../IProperty";
-
-export interface ITabularProperty extends IProperty {
-
- /**
- * The property's value.
- */
- readonly value: ReadonlyMap;
-
- /**
- * The table's property state.
- */
- readonly properties: ReadonlyArray;
-
-
- ///////////////////////////////////////////////////////////////////////////
- // 1. Value Manipulation ////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////
-
-
- /**
- * Returns a row's id.
- * @param index
- * The row's index.
- * @returns
- * The row's id, undefined if no row at `index`.
- */
- getId(index: number): string | undefined;
-
- /**
- * Returns a row's index.
- * @param id
- * The row's id.
- * @returns
- * The row's index, -1 if no row matches `id`.
- */
- getIndex(id: string): number;
-
- /**
- * Creates a new table row.
- * @returns
- * The row's id and properties.
- * @throws { Error }
- * If the table's `template` defines a non-atomic property.
- */
- createRow(): [string, IAtomicProperty[]];
-
- /**
- * Creates a new table row from a set of values.
- * @returns
- * The row's id and properties.
- * @param values
- * The row's values.
- * @throws { Error }
- * If the table's `template` defines a non-atomic property.
- */
- createRow(values: { [key: string]: any }): [string, IAtomicProperty[]];
-
- /**
- * Inserts a row into the table property.
- * @param row
- * The row to insert.
- * @param index
- * The row's index.
- * @throws { Error }
- * If `row` does not match the table's property schema.
- */
- insertRow(row: [string, IAtomicProperty[]], index?: number): void;
-
- /**
- * Moves a row to another location in the table.
- * @param src
- * The row's current index.
- * @param dst
- * The row's new index.
- */
- moveRow(src: number, dst: number): void;
-
- /**
- * Removes a row from the table property.
- * @param index
- * The row's index.
- * @returns
- * True if the row was removed, false otherwise.
- */
- deleteRow(index: number): boolean;
-
- /**
- * Removes a row from the table property.
- * @param id
- * The row's id.
- * @returns
- * True if the row was removed, false otherwise.
- */
- deleteRow(id: string): boolean;
-
- /**
- * Captures a snapshot of a column.
- * @param id
- * The column's id.
- * @returns
- * The column snapshot.
- */
- captureColumnSnapshot(id: string): ColumnSnapshot;
-
- /**
- * Captures a snapshot of a column with the given sort order applied.
- * @param id
- * The column's id.
- * @param sort
- * The sort order to use.
- * @returns
- * The column snapshot.
- * @throws { Error }
- * If column does not exist.
- * If column properties mismatch column type.
- * If column is a non-atomic property type.
- */
- captureColumnSnapshot(id: string, sort: Sort): ColumnSnapshot;
-
- /**
- * Applies a column snapshot to the table.
- * @param snapshot
- * The snapshot to apply.
- * @throws { Error }
- * If the snapshot does not align with the table's current state.
- * If the snapshot's column doesn't exist within the table.
- */
- applyColumnSnapshot(snapshot: ColumnSnapshot): void;
-
- /**
- * Creates a new command.
- */
- newCommand(): void;
-
-
- ///////////////////////////////////////////////////////////////////////////
- // 2. Events ////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////
-
-
- /**
- * Adds an event listener to the property.
- * @param event
- * The event to subscribe to.
- * @param callback
- * The function to call once the event has fired.
- */
- on(event: K, callback: TabularPropertyEvents[K]): void;
-
- /**
- * Adds an event listener to the property that will be fired once and then
- * removed.
- * @param event
- * The event to subscribe to.
- * @param callback
- * The function to call once the event has fired.
- */
- once(event: K, callback: TabularPropertyEvents[K]): void;
-
- /**
- * Removes all event listeners associated with a given event. If no event
- * name is specified, all event listeners are removed.
- * @param event
- * The name of the event.
- */
- removeAllListeners(event?: K): void;
-
-
- ///////////////////////////////////////////////////////////////////////////
- // 3. toString //////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////
-
-
- /**
- * Returns a string representation of the property.
- * @returns
- * A string representation of the property.
- */
- toString(): string | undefined
-
-}
-
-
-///////////////////////////////////////////////////////////////////////////////
-// Internal Types ///////////////////////////////////////////////////////////
-///////////////////////////////////////////////////////////////////////////////
-
-
-// Event types
-export interface TabularPropertyEvents extends PropertyEvents {
- "row-select" : (id: string, property: IAtomicProperty) => void,
- "row-deselect" : (id: string, property: IAtomicProperty) => void,
- "row-insert" : (id: string, property: IAtomicProperty[]) => void,
- "row-delete" : (id: string, property: IAtomicProperty[]) => void,
- "row-update" : (id: string, property: IAtomicProperty, newValue: any, oldValue: any) => void
-}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Page/Property/TabularProperty/TablePropertyState.ts b/src/cti_authoring_tool/src/assets/scripts/Page/Property/TabularProperty/TableColumnState.ts
similarity index 91%
rename from src/cti_authoring_tool/src/assets/scripts/Page/Property/TabularProperty/TablePropertyState.ts
rename to src/cti_authoring_tool/src/assets/scripts/Page/Property/TabularProperty/TableColumnState.ts
index d556d34..bb16f7c 100644
--- a/src/cti_authoring_tool/src/assets/scripts/Page/Property/TabularProperty/TablePropertyState.ts
+++ b/src/cti_authoring_tool/src/assets/scripts/Page/Property/TabularProperty/TableColumnState.ts
@@ -1,6 +1,6 @@
import { Sort } from "./Sort";
-export interface TablePropertyState {
+export interface TableColumnState {
/**
* The property's id.
diff --git a/src/cti_authoring_tool/src/assets/scripts/Page/Property/TabularProperty/TabularProperty.ts b/src/cti_authoring_tool/src/assets/scripts/Page/Property/TabularProperty/TabularProperty.ts
index c7704a9..e2629f5 100644
--- a/src/cti_authoring_tool/src/assets/scripts/Page/Property/TabularProperty/TabularProperty.ts
+++ b/src/cti_authoring_tool/src/assets/scripts/Page/Property/TabularProperty/TabularProperty.ts
@@ -1,88 +1,91 @@
-import { PageSection } from "../../PageSection";
-import { Crypto, String } from "@/assets/scripts/Utilities";
+import * as Crypto from "@/assets/scripts/Utilities";
import { ColumnSnapshot } from "./ColumnSnapshot";
-import { ITabularProperty } from "./ITabularProperty";
-import { AtomicPagePropertyTemplate, PropertyType, TabularPropertyRowValue, TabularPropertyTemplate } from "../../../AppConfiguration";
-import { AtomicProperty, DateTimeProperty, EnumProperty, NumberProperty, Property, Sort, StringProperty, TablePropertyState } from "..";
+import { PropertyParameters } from "../PropertyParameters";
+import { Plugin, PluginManager } from "../../Plugins";
+import { TabularPropertyAssembler } from "./TabularPropertyAssembler";
+import {
+ Sort,
+ Property,
+ PropertyAssembler,
+ AtomicProperty,
+ EnumProperty,
+ TimeProperty,
+ DateProperty,
+ DateTimeProperty,
+ FloatProperty,
+ IntegerProperty,
+ NumberProperty,
+ StringProperty,
+ TableColumnState
+} from "..";
-export abstract class TabularProperty extends Property implements ITabularProperty {
-
- // TODO: Consume update events from child properties
- // TODO: Link row events
+export abstract class TabularProperty extends Property {
/**
* The property's value.
*/
- public value: Map;
+ protected _value: Map;
+
+ /**
+ * The table's default row.
+ */
+ protected _defaultRow: AtomicProperty[];
/**
- * The table's property state.
+ * The table's column state.
*/
- public properties: TablePropertyState[];
+ protected _columnState: TableColumnState[];
/**
- * The table's property templates.
+ * The property's plugin manager.
+ */
+ protected _plugins: PluginManager | null;
+
+
+ /**
+ * The property's value.
*/
- protected readonly _templates: AtomicPagePropertyTemplate[];
+ public get value(): ReadonlyMap {
+ return this._value;
+ }
+ /**
+ * The table's column state.
+ */
+ public get columnState(): ReadonlyArray {
+ return this._columnState;
+ }
+
/**
* Creates a new {@link TabularProperty}.
- * @param section
- * The property's section.
- * @param template
- * The property's template.
- * @throws { Error }
- * If `template` defines a non-atomic property.
+ * @param params
+ * The property's parameters.
*/
- constructor(section: PageSection, template: TabularPropertyTemplate);
+ constructor(params: PropertyParameters);
/**
* Creates a new {@link TabularProperty}.
- * @param section
- * The property's section.
- * @param template
- * The property's template.
- * @param value
- * The property's value.
- * @throws { Error }
- * If `template` defines a non-atomic property.
+ * @param params
+ * The property's parameters.
+ * @param assembler
+ * The property's assembler.
*/
- constructor(section: PageSection, template: TabularPropertyTemplate, value: TabularPropertyRowValue[]);
- constructor(section: PageSection, template: TabularPropertyTemplate, value?: TabularPropertyRowValue[]) {
- super(section, template);
- this.value = new Map();
- this.properties = [];
- this._templates = [];
- // Configure header
- let templates = template.properties;
- for(let t of templates) {
- this._templates.push(structuredClone(t));
- this.properties.push({
- id : t.id ?? String.formatId(t.name),
- name : t.name,
- sort : Sort.None,
- col : Array.isArray(t.col) ? [...t.col] : t.col,
- row : Array.isArray(t.row) ? [...t.row] : t.row,
- });
+ constructor(params: PropertyParameters, assembler?: TabularPropertyAssembler);
+ constructor(params: PropertyParameters, assembler?: TabularPropertyAssembler) {
+ super(params, assembler);
+ this._value = new Map();
+ this._plugins = null;
+ this._defaultRow = [];
+ this._columnState = [];
+ if(assembler) {
+ this.__prepareAssembler(assembler);
}
- // Configure values
- if(value !== undefined) {
- for(let v of value) {
- this.insertRow(this.createRow(v));
- }
- } else if(template.default !== undefined) {
- for(let v of template.default) {
- this.insertRow(this.createRow(v));
- }
- }
- // Initialize Plugins
- this.initializePlugins(template);
}
///////////////////////////////////////////////////////////////////////////
- /// 1. ITabularProperty Methods /////////////////////////////////////////
+ /// 1. Row Management ///////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
@@ -93,8 +96,8 @@ export abstract class TabularProperty extends Property implements ITabularProper
* @returns
* The row's id, undefined if no row at `index`.
*/
- public getId(index: number): string | undefined {
- return [...this.value.keys()][index];
+ public getRowId(index: number): string | undefined {
+ return [...this._value.keys()][index];
}
/**
@@ -104,8 +107,8 @@ export abstract class TabularProperty extends Property implements ITabularProper
* @returns
* The row's index, -1 if no row matches `id`.
*/
- public getIndex(id: string): number {
- return [...this.value.keys()].findIndex(o => o === id);
+ public getRowIndex(id: string): number {
+ return [...this._value.keys()].findIndex(o => o === id);
}
/**
@@ -117,8 +120,8 @@ export abstract class TabularProperty extends Property implements ITabularProper
*/
public getRow(id: string): [string, AtomicProperty[]] | undefined {
let result: [string, AtomicProperty[]] | undefined;
- if(this.value.has(id)) {
- result = [id, this.value.get(id)!]
+ if(this._value.has(id)) {
+ result = [id, this._value.get(id)!]
}
return result;
}
@@ -127,8 +130,6 @@ export abstract class TabularProperty extends Property implements ITabularProper
* Creates a new table row.
* @returns
* The row's id and properties.
- * @throws { Error }
- * If the table's `template` defines a non-atomic property.
*/
public createRow(): [string, AtomicProperty[]];
@@ -138,20 +139,25 @@ export abstract class TabularProperty extends Property implements ITabularProper
* The row's id and properties.
* @param values
* The row's values.
- * @throws { Error }
- * If the table's `template` defines a non-atomic property.
*/
public createRow(values: { [key: string]: any }): [string, AtomicProperty[]];
public createRow(values?: { [key: string]: any }): [string, AtomicProperty[]] {
let row = [];
- for(let template of this._templates) {
- let value = values && template.id && values[template.id];
- let prop = Property.create(this._section, template, value);
- if(prop instanceof AtomicProperty) {
- row.push(prop);
- } else {
- throw new Error(`'${ prop.id }' is not an atomic property.`);
+ for(let cell of this._defaultRow) {
+ let asm = new PropertyAssembler();
+ let prop = cell.clone(asm);
+ if(
+ values && cell.id in values &&
+ (
+ prop instanceof DateTimeProperty ||
+ prop instanceof StringProperty ||
+ prop instanceof NumberProperty ||
+ prop instanceof EnumProperty
+ )
+ ) {
+ prop.value = values[cell.id];
}
+ row.push(prop);
}
return [Crypto.randomUUID(), row];
}
@@ -163,28 +169,33 @@ export abstract class TabularProperty extends Property implements ITabularProper
* @param index
* The row's index.
* @throws { Error }
- * If `row` does not match the table's property schema.
+ * If `row` does not match the table's structure.
*/
public insertRow(row: [string, AtomicProperty[]], index?: number) {
+ let assembler = this.__prepareAssembler();
// Create row
let props: AtomicProperty[] = [];
- for(let template of this._templates) {
+ for(let cell of this._defaultRow) {
// TODO: Need better comparison
- let p = row[1].find(o => o.id === template.id);
+ let p = row[1].find(o => o.id === cell.id);
if(p) {
props.push(p);
} else {
- throw Error("Row does not match the table's property schema.")
+ throw Error("Row does not match the table's structure.")
}
}
+ for(let prop of props) {
+ prop.__prepareAssembler().attachToTabularProperty(assembler);
+ }
// Insert row
if(index === undefined) {
- this.value.set(row[0], props);
+ this._value.set(row[0], props);
} else {
- let v = [...this.value.entries()];
+ let v = [...this._value.entries()];
v.splice(index, 0, [row[0], props]);
- this.value = new Map(v);
+ this._value = new Map(v);
}
+ this.emit("insert-row", row[0], [...props]);
}
/**
@@ -196,11 +207,12 @@ export abstract class TabularProperty extends Property implements ITabularProper
*/
public moveRow(src: number, dst: number) {
// Get rows
- let rows = [...this.value.entries()]
+ let rows = [...this._value.entries()]
// Move row
rows.splice(dst, 0, rows.splice(src, 1)[0]);
// Update rows
- this.value = new Map(rows);
+ this._value = new Map(rows);
+ this.emit("move-row", src, dst);
}
/**
@@ -220,13 +232,21 @@ export abstract class TabularProperty extends Property implements ITabularProper
* True if the row was removed, false otherwise.
*/
public deleteRow(id: string): boolean;
- public deleteRow(_: string | number): boolean {
- if(typeof _ === "number") {
- _ = [...this.value.keys()][_]
+ public deleteRow(id: string | number): boolean {
+ if(typeof id === "number") {
+ id = [...this._value.keys()][id]
}
- return _ !== undefined ? this.value.delete(_) : false;
+ let result = id !== undefined ? this._value.delete(id) : false;
+ this.emit("delete-row", id);
+ return result;
}
+
+ ///////////////////////////////////////////////////////////////////////////
+ /// 2. Column Management ////////////////////////////////////////////////
+ ///////////////////////////////////////////////////////////////////////////
+
+
/**
* Captures a snapshot of a column.
* @param id
@@ -252,16 +272,16 @@ export abstract class TabularProperty extends Property implements ITabularProper
public captureColumnSnapshot(id: string, sort: Sort): ColumnSnapshot;
public captureColumnSnapshot(id: string, sort?: Sort): ColumnSnapshot {
// Resolve column
- let column = this.properties.findIndex(o => o.id === id);
+ let column = this._columnState.findIndex(o => o.id === id);
if(column === -1) {
throw new Error(`Column '${ id }' does not exist.`);
}
// If no sort order, capture as is
if(sort === undefined) {
return {
- id: this.properties[column].id,
- sort: this.properties[column].sort,
- ids: [...this.value.keys()]
+ id: this._columnState[column].id,
+ sort: this._columnState[column].sort,
+ ids: [...this._value.keys()]
}
}
// If sort order, capture applied sort order
@@ -273,16 +293,16 @@ export abstract class TabularProperty extends Property implements ITabularProper
break;
case Sort.Ascending:
dir = -1
- break;
+ break;``
case Sort.None:
dir = 0;
break;
}
- switch(this._templates[column].type) {
- case PropertyType.String:
- ids = [...this.value.keys()].sort((a,b) => {
- let rowA = this.value.get(a)![column];
- let rowB = this.value.get(b)![column];
+ switch(this._defaultRow[column].constructor.name) {
+ case StringProperty.name:
+ ids = [...this._value.keys()].sort((a,b) => {
+ let rowA = this._value.get(a)![column];
+ let rowB = this._value.get(b)![column];
if(
rowA instanceof StringProperty &&
rowB instanceof StringProperty
@@ -295,11 +315,11 @@ export abstract class TabularProperty extends Property implements ITabularProper
}
});
break;
- case PropertyType.Float:
- case PropertyType.Integer:
- ids = [...this.value.keys()].sort((a,b) => {
- let rowA = this.value.get(a)![column];
- let rowB = this.value.get(b)![column];
+ case FloatProperty.name:
+ case IntegerProperty.name:
+ ids = [...this._value.keys()].sort((a,b) => {
+ let rowA = this._value.get(a)![column];
+ let rowB = this._value.get(b)![column];
if(
rowA instanceof NumberProperty &&
rowB instanceof NumberProperty
@@ -312,10 +332,12 @@ export abstract class TabularProperty extends Property implements ITabularProper
}
});
break;
- case PropertyType.Date:
- ids = [...this.value.keys()].sort((a,b) => {
- let rowA = this.value.get(a)![column];
- let rowB = this.value.get(b)![column];
+ case DateProperty.name:
+ case TimeProperty.name:
+ case DateTimeProperty.name:
+ ids = [...this._value.keys()].sort((a,b) => {
+ let rowA = this._value.get(a)![column];
+ let rowB = this._value.get(b)![column];
if(
rowA instanceof DateTimeProperty &&
rowB instanceof DateTimeProperty
@@ -328,10 +350,10 @@ export abstract class TabularProperty extends Property implements ITabularProper
}
});
break;
- case PropertyType.Enum:
- ids = [...this.value.keys()].sort((a,b) => {
- let rowA = this.value.get(a)![column];
- let rowB = this.value.get(b)![column];
+ case EnumProperty.name:
+ ids = [...this._value.keys()].sort((a,b) => {
+ let rowA = this._value.get(a)![column];
+ let rowB = this._value.get(b)![column];
if(
rowA instanceof EnumProperty &&
rowB instanceof EnumProperty
@@ -347,7 +369,7 @@ export abstract class TabularProperty extends Property implements ITabularProper
default:
throw new Error(`Cannot sort non-atomic property type.`);
}
- return { id: this._templates[column].id!, sort, ids }
+ return { id: this._defaultRow[column].id, sort, ids }
}
/**
@@ -360,16 +382,16 @@ export abstract class TabularProperty extends Property implements ITabularProper
*/
public applyColumnSnapshot(snapshot: ColumnSnapshot) {
// Validate snapshot
- let isValid = this.value.size === snapshot.ids.length;
+ let isValid = this._value.size === snapshot.ids.length;
for(let id of snapshot.ids) {
- isValid &&= this.value.has(id);
+ isValid &&= this._value.has(id);
}
if(!isValid) {
throw new Error("Invalid snapshot.")
}
// Resolve column
let id = snapshot.id;
- let column = this.properties.find(o => o.id === id);
+ let column = this._columnState.find(o => o.id === id);
if(!column) {
throw new Error(`Column '${ id }' does not exist.`);
}
@@ -378,34 +400,135 @@ export abstract class TabularProperty extends Property implements ITabularProper
// Apply row ordering
let order: [string, AtomicProperty[]][] = [];
for(let id of snapshot.ids) {
- order.push([id, this.value.get(id)!]);
+ order.push([id, this._value.get(id)!]);
}
- this.value = new Map(order);
+ this._value = new Map(order);
+ this.emit("reorder-row");
}
+
+ ///////////////////////////////////////////////////////////////////////////
+ /// 3. Plugin Management ////////////////////////////////////////////////
+ ///////////////////////////////////////////////////////////////////////////
+
+
/**
- * Creates a new command.
+ * Attempts to install a plugin into the property.
+ * @param plugin
+ * The plugin to install.
+ * @returns
+ * True if the plugin was successfully installed, false otherwise.
*/
- newCommand(): void {
- // TODO: Implement command construct
- throw new Error("Method not implemented.");
+ public tryInstallPlugin(plugin: Plugin): boolean {
+ let result;
+ // Don't allocate manager until absolutely necessary
+ if(this._plugins === null) {
+ this._plugins = new PluginManager(this, this.root);
+ }
+ result = this._plugins.tryInstallPlugin(plugin);
+ // Deallocate manager if no plugins were installed
+ if(this._plugins.length === 0) {
+ this._plugins = null;
+ }
+ return result;
}
+ /**
+ * Attempts to install a list of plugins into the property.
+ * @param plugin
+ * The plugins to install.
+ * @returns
+ * True if all plugins were successfully installed, false otherwise.
+ */
+ public tryInstallPlugins(plugins: Plugin[]): boolean {
+ let result = true;
+ for(let plugin of plugins) {
+ result &&= this.tryInstallPlugin(plugin);
+ }
+ return result;
+ }
+
+
+
+ ///////////////////////////////////////////////////////////////////////////
+ /// 4. toString /////////////////////////////////////////////////////////
+ ///////////////////////////////////////////////////////////////////////////
+
+
/**
* Returns a string representation of the property.
* @returns
* A string representation of the property.
*/
public override toString(): string | undefined {
- let primaryColumn = this._templates.findIndex(o => o.is_primary);
- if(primaryColumn === -1 || this.value.size === 0) {
- return undefined;
- }
- let name = [...this.value.values()]
- .map(o => o[primaryColumn].toString())
- .filter(Boolean)
- .join(", ")
- return name || undefined;
+ return "[ Not Supported ]";
+ // let primaryColumn = this._templates.findIndex(o => o.is_primary);
+ // if(primaryColumn === -1 || this._value.size === 0) {
+ // return undefined;
+ // }
+ // let name = [...this._value.values()]
+ // .map(o => o[primaryColumn].toString())
+ // .filter(Boolean)
+ // .join(", ")
+ // return name || undefined;
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////
+ /// 5. Assembler Preparation ////////////////////////////////////////////
+ ///////////////////////////////////////////////////////////////////////////
+
+
+ /**
+ * Prepares an assembler for the property.
+ * @returns
+ * The property's assembler.
+ * @remarks
+ * Page API use only. Do not use.
+ * @internal
+ */
+ public override __prepareAssembler(): TabularPropertyAssembler
+
+ /**
+ * Prepares an assembler for the property.
+ * @param assembler
+ * The assembler to use.
+ * @returns
+ * The property's assembler.
+ * @remarks
+ * Page API use only. Do not use.
+ * @internal
+ */
+ public override __prepareAssembler(
+ assembler?: TabularPropertyAssembler
+ ): TabularPropertyAssembler;
+
+ public override __prepareAssembler(
+ assembler: TabularPropertyAssembler = new TabularPropertyAssembler()
+ ): TabularPropertyAssembler {
+ // Prepare property assembler
+ super.__prepareAssembler(assembler);
+ // Prepare tabular property assembler
+ assembler.__injectTabularAccessor({
+ property: this,
+ setDefaultRow: (row: AtomicProperty[]) => {
+ // Reset values
+ this._value = new Map();
+ // Set default row
+ this._defaultRow = row;
+ // Set column state
+ for(let cell of this._defaultRow) {
+ this._columnState.push({
+ id : cell.id,
+ name : cell.name,
+ sort : Sort.None,
+ col : Array.isArray(cell.col) ? [...cell.col] : cell.col,
+ row : Array.isArray(cell.row) ? [...cell.row] : cell.row,
+ });
+ }
+ }
+ });
+ return assembler;
}
}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Page/Property/TabularProperty/TabularPropertyAccessor.ts b/src/cti_authoring_tool/src/assets/scripts/Page/Property/TabularProperty/TabularPropertyAccessor.ts
new file mode 100644
index 0000000..5703893
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/Page/Property/TabularProperty/TabularPropertyAccessor.ts
@@ -0,0 +1,18 @@
+import { AtomicProperty } from "../AtomicProperty";
+import { TabularProperty } from "./TabularProperty";
+
+export interface TabularPropertyAccessor {
+
+ /**
+ * The tabular property.
+ */
+ property: TabularProperty;
+
+ /**
+ * Sets the property's default row.
+ * @param row
+ * The property's default row.
+ */
+ setDefaultRow: (row: AtomicProperty[]) => void;
+
+}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Page/Property/TabularProperty/TabularPropertyAssembler.ts b/src/cti_authoring_tool/src/assets/scripts/Page/Property/TabularProperty/TabularPropertyAssembler.ts
new file mode 100644
index 0000000..4f067f1
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/Page/Property/TabularProperty/TabularPropertyAssembler.ts
@@ -0,0 +1,62 @@
+import { AtomicProperty } from "../AtomicProperty";
+import { PropertyAssembler } from "../PropertyAssembler";
+import { TabularProperty } from "./TabularProperty";
+import { TabularPropertyAccessor } from "./TabularPropertyAccessor";
+
+export class TabularPropertyAssembler extends PropertyAssembler {
+
+ /**
+ * The tabular property's accessor.
+ */
+ private _tabularAccessor: TabularPropertyAccessor | null;
+
+
+ /**
+ * The assembler's property.
+ */
+ public override get property(): TabularProperty {
+ return this.tabularAccessor.property;
+ }
+
+ /**
+ * The tabular property's accessor.
+ */
+ private get tabularAccessor(): TabularPropertyAccessor {
+ if(this._tabularAccessor === null) {
+ throw new Error("Assembler is not configured with a tabular property.");
+ }
+ return this._tabularAccessor;
+ }
+
+
+ /**
+ * Creates a new {@link TabularPropertyAssembler}.
+ */
+ constructor() {
+ super();
+ this._tabularAccessor = null;
+ }
+
+
+ /**
+ * Injects a tabular property's private resources into the assembler.
+ * @param accessor
+ * The tabular property's accessor.
+ * @remarks
+ * Page API use only. Do not use.
+ * @internal
+ */
+ public __injectTabularAccessor(accessor: TabularPropertyAccessor) {
+ this._tabularAccessor = accessor;
+ }
+
+ /**
+ * Sets the tabular property's default row.
+ * @param row
+ * The default row.
+ */
+ public setDefaultRow(row: AtomicProperty[]) {
+ this.tabularAccessor.setDefaultRow(row);
+ }
+
+}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Page/Property/TabularProperty/index.ts b/src/cti_authoring_tool/src/assets/scripts/Page/Property/TabularProperty/index.ts
new file mode 100644
index 0000000..4e892aa
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/Page/Property/TabularProperty/index.ts
@@ -0,0 +1,5 @@
+export * from "./ColumnSnapshot";
+export * from "./Sort";
+export * from "./TableColumnState";
+export * from "./TabularProperty";
+export * from "./TabularPropertyAssembler";
diff --git a/src/cti_authoring_tool/src/assets/scripts/Page/Property/index.ts b/src/cti_authoring_tool/src/assets/scripts/Page/Property/index.ts
index 6b3a1f3..ecc205a 100644
--- a/src/cti_authoring_tool/src/assets/scripts/Page/Property/index.ts
+++ b/src/cti_authoring_tool/src/assets/scripts/Page/Property/index.ts
@@ -1,29 +1,11 @@
-/**
- * Developers Note:
- * This file explicitly defines the module loading order. In order to prevent
- * circular dependencies, all files that need access to these modules should
- * import them directly from this file, not the source files themselves.
- */
-
-export * from "./IProperty";
export * from "./Property";
-export * from "./AtomicProperty/IAtomicProperty";
-export * from "./AtomicProperty/AtomicProperty";
-export * from "./DateTimeProperty/IDateTimeProperty";
-export * from "./DateTimeProperty/DateTimeProperty";
-export * from "./StringProperty/IStringProperty";
-export * from "./StringProperty/StringProperty";
-export * from "./NumberProperty/INumberProperty";
-export * from "./NumberProperty/NumberProperty";
-export * from "./EnumProperty/IEnumProperty";
-export * from "./EnumProperty/EnumProperty";
-export * from "./TabularProperty/Sort";
-export * from "./TabularProperty/ColumnSnapshot";
-export * from "./TabularProperty/TablePropertyState";
-export * from "./TabularProperty/TabularProperty";
-export * from "./BasicTableProperty/IBasicTableProperty";
-export * from "./BasicTableProperty/BasicTableProperty";
-export * from "./ComplexTableProperty/FormattedText";
-export * from "./ComplexTableProperty/SummaryParser";
-export * from "./ComplexTableProperty/IComplexTableProperty";
-export * from "./ComplexTableProperty/ComplexTableProperty";
+export * from "./PropertyAssembler";
+export * from "./PropertyParameters"
+export * from "./AtomicProperty";
+export * from "./DateTimeProperty";
+export * from "./StringProperty";
+export * from "./NumberProperty";
+export * from "./EnumProperty";
+export * from "./TabularProperty";
+export * from "./BasicTableProperty";
+export * from "./ComplexTableProperty";
diff --git a/src/cti_authoring_tool/src/assets/scripts/Page/Section/Section.ts b/src/cti_authoring_tool/src/assets/scripts/Page/Section/Section.ts
new file mode 100644
index 0000000..c382f12
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/Page/Section/Section.ts
@@ -0,0 +1,202 @@
+import { Page } from "../Page";
+import { PageElement } from "../PageElement";
+import { SectionLayout } from "./SectionLayout";
+import { SectionAssembler } from "./SectionAssembler";
+import { SectionParameters } from "./SectionParameters";
+import { Plugin, PluginManager } from "../Plugins";
+import { Property, PropertyAssembler } from "../Property";
+
+export class Section extends PageElement {
+
+ /**
+ * The section's id.
+ */
+ public readonly id: string;
+
+ /**
+ * The section's name.
+ */
+ public readonly name: string | null;
+
+ /**
+ * The section's export path.
+ */
+ public readonly path: string;
+
+ /**
+ * The section's layout.
+ */
+ public readonly layout: SectionLayout;
+
+ /**
+ * The section's properties.
+ */
+ public readonly properties: ReadonlyMap;
+
+ /**
+ * The section's plugins.
+ */
+ private _plugins: PluginManager | null;
+
+
+ /**
+ * Creates a new {@link Section}.
+ * @param params
+ * The section's parameters.
+ */
+ constructor(params: SectionParameters);
+
+ /**
+ * Creates a new {@link Section}.
+ * @param params
+ * The section's parameters.
+ * @param assembler
+ * The section's assembler.
+ */
+ constructor(params: SectionParameters, assembler?: SectionAssembler);
+ constructor(params: SectionParameters, assembler?: SectionAssembler) {
+ super();
+ // Configure state
+ this.id = params.id;
+ this.name = params.name ?? null;
+ this.path = params.path ?? params.id;
+ this.layout = {
+ rows: params.layout.rows,
+ cols: params.layout.cols
+ }
+ this.properties = new Map();
+ this._parent = null;
+ this._plugins = null;
+ // Configure assembler
+ if(assembler) {
+ this.__prepareAssembler(assembler);
+ }
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////
+ /// 1. Section Cloning //////////////////////////////////////////////////
+ ///////////////////////////////////////////////////////////////////////////
+
+
+ /**
+ * Clones the section.
+ * @returns
+ * The cloned section.
+ */
+ public clone(): Section
+
+ /**
+ * Clones the section.
+ * @param assembler
+ * The cloned section's assembler.
+ * @returns
+ * The cloned section.
+ */
+ public clone(assembler?: SectionAssembler): Section;
+ public clone(assembler?: SectionAssembler): Section {
+ assembler ??= new SectionAssembler();
+ // Create section
+ let section = new Section({
+ id : this.id,
+ name : this.name,
+ path : this.path,
+ layout: {
+ rows : this.layout.rows,
+ cols : this.layout.cols
+ }
+ }, assembler);
+ // Clone properties
+ for(let property of this.properties.values()) {
+ let propertyAssembler = new PropertyAssembler();
+ property.clone(propertyAssembler);
+ assembler.attachProperty(propertyAssembler);
+ }
+ // Clone plugins
+ this._plugins?.forEach(({ plugin }) => {
+ section.tryInstallPlugin(plugin)
+ });
+ // Return
+ return section;
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////
+ /// 2. Plugin Management ////////////////////////////////////////////////
+ ///////////////////////////////////////////////////////////////////////////
+
+
+ /**
+ * Attempts to install a plugin into the property.
+ * @param plugin
+ * The plugin to install.
+ * @returns
+ * True if the plugin was successfully installed, false otherwise.
+ */
+ public tryInstallPlugin(plugin: Plugin): boolean {
+ let result;
+ // Don't allocate manager until absolutely necessary
+ if(this._plugins === null) {
+ this._plugins = new PluginManager(this, this.root);
+ }
+ result = this._plugins.tryInstallPlugin(plugin);
+ // Deallocate manager if no plugins were installed
+ if(this._plugins.length === 0) {
+ this._plugins = null;
+ }
+ return result;
+ }
+
+ /**
+ * Attempts to install a list of plugins into the property.
+ * @param plugin
+ * The plugins to install.
+ * @returns
+ * True if all plugins were successfully installed, false otherwise.
+ */
+ public tryInstallPlugins(plugins: Plugin[]): boolean {
+ let result = true;
+ for(let plugin of plugins) {
+ result &&= this.tryInstallPlugin(plugin);
+ }
+ return result;
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////
+ /// 3. Assembler Preparation ////////////////////////////////////////////
+ ///////////////////////////////////////////////////////////////////////////
+
+
+ /**
+ * Prepares an assembler for the section.
+ * @returns
+ * The section's assembler.
+ * @remarks
+ * Page API use only. Do not use.
+ * @internal
+ */
+ public __prepareAssembler(): SectionAssembler
+
+ /**
+ * Prepares an assembler for the section.
+ * @param assembler
+ * The assembler to use.
+ * @returns
+ * The section's assembler.
+ * @remarks
+ * Page API use only. Do not use.
+ * @internal
+ */
+ public __prepareAssembler(assembler?: SectionAssembler): SectionAssembler;
+ public __prepareAssembler(assembler: SectionAssembler = new SectionAssembler()): SectionAssembler {
+ assembler.__injectAccessor({
+ section: this,
+ getParent: () => this._parent,
+ setParent: (p: Page | null) => this._parent = p,
+ properties: this.properties as Map
+ });
+ return assembler;
+ }
+
+}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Page/Section/SectionAccessor.ts b/src/cti_authoring_tool/src/assets/scripts/Page/Section/SectionAccessor.ts
new file mode 100644
index 0000000..6f4bca0
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/Page/Section/SectionAccessor.ts
@@ -0,0 +1,32 @@
+import { Page } from "../Page";
+import { Section } from ".";
+import { Property } from "../Property";
+import { PageElement } from "../PageElement";
+
+export interface SectionAccessor {
+
+ /**
+ * The section.
+ */
+ section: Section;
+
+ /**
+ * Gets the section's parent.
+ * @returns
+ * The section's parent.
+ */
+ getParent: () => PageElement | null;
+
+ /**
+ * Sets the section's parent.
+ * @param p
+ * The section's parent.
+ */
+ setParent: (p: Page | null) => void;
+
+ /**
+ * The section's properties.
+ */
+ properties: Map;
+
+}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Page/Section/SectionAssembler.ts b/src/cti_authoring_tool/src/assets/scripts/Page/Section/SectionAssembler.ts
new file mode 100644
index 0000000..40ac08e
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/Page/Section/SectionAssembler.ts
@@ -0,0 +1,228 @@
+import { Section } from ".";
+import { PageAssembler } from "../PageAssembler";
+import { SectionAccessor } from "./SectionAccessor";
+import { PropertyAssembler } from "../Property/PropertyAssembler";
+
+export class SectionAssembler {
+
+ /**
+ * The section's accessor.
+ */
+ private _accessor: SectionAccessor | null;
+
+ /**
+ * The assembler's parent.
+ */
+ private _parentAssembler: PageAssembler | null;
+
+ /**
+ * The assembler's properties.
+ */
+ private _propertyAssemblers: Map;
+
+
+ /**
+ * The assembler's section.
+ */
+ public get section(): Section {
+ return this.accessor.section;
+ }
+
+ /**
+ * The assembler's parent.
+ */
+ public get parent(): PageAssembler | null {
+ return this._parentAssembler;
+ }
+
+ /**
+ * The assembler's properties.
+ */
+ public get properties(): ReadonlyMap {
+ return this._propertyAssemblers;
+ }
+
+ /**
+ * The section's accessor.
+ */
+ private get accessor(): SectionAccessor {
+ if(this._accessor === null) {
+ throw new Error("Assembler is not configured with a section.");
+ }
+ return this._accessor;
+ }
+
+
+ /**
+ * Creates a new {@link SectionAssembler}.
+ */
+ constructor() {
+ this._accessor = null;
+ this._parentAssembler = null;
+ this._propertyAssemblers = new Map();
+ }
+
+
+ /**
+ * Injects a section's private resources into the assembler.
+ * @param accessor
+ * The section's accessor.
+ * @remarks
+ * Page API use only. Do not use.
+ * @internal
+ */
+ public __injectAccessor(accessor: SectionAccessor) {
+ this._accessor = accessor;
+ this._parentAssembler = null;
+ this._propertyAssemblers = new Map();
+ }
+
+ /**
+ * Adds the section to a page.
+ * @param asm
+ * The page's assembler.
+ */
+ public attachToPage(asm: PageAssembler) {
+ // Validate
+ if(this.belongsToPage(asm)) {
+ return;
+ }
+ // Detach existing parent, if needed
+ if(this.belongsToPage()) {
+ this.detachFromPage();
+ }
+ // Attach parent
+ this.accessor.setParent(asm.page);
+ this._parentAssembler = asm;
+ // Attach section
+ asm.attachSection(this);
+ }
+
+ /**
+ * Removes the section from its current page.
+ */
+ public detachFromPage() {
+ // Validate
+ if(!this.belongsToPage()) {
+ return;
+ }
+ let parent = this._parentAssembler!;
+ // Detach parent
+ this.accessor.setParent(null);
+ this._parentAssembler = null;
+ // Detach section
+ parent.detachSection(this);
+ }
+
+ /**
+ * Tests if the section belongs to a page.
+ * @returns
+ * True if the section belongs to a page, false otherwise.
+ */
+ public belongsToPage(): boolean;
+
+ /**
+ * Tests if the section belongs to the given page.
+ * @param asm
+ * The page's assembler.
+ * @returns
+ * True if the section belongs to the given page, false otherwise.
+ */
+ public belongsToPage(asm: PageAssembler): boolean;
+ public belongsToPage(asm?: PageAssembler): boolean {
+ let parent = this.accessor.getParent();
+ if(parent === null) {
+ return false;
+ } else if(asm === undefined) {
+ return true;
+ }
+ return parent.instance === asm.page.instance;
+ }
+
+ /**
+ * Adds a property to the section.
+ * @param asm
+ * The property's assembler.
+ */
+ public attachProperty(asm: PropertyAssembler) {
+ // Validate
+ if(this.includesProperty(asm)) {
+ return;
+ }
+ // Detach existing child, if needed
+ let id = asm.property.id;
+ if(this.includesProperty(id)) {
+ this.detachProperty(id);
+ }
+ // Attach property
+ this.accessor.properties.set(id, asm.property);
+ this._propertyAssemblers.set(id, asm);
+ // Attach parent
+ asm.attachToSection(this);
+ }
+
+ /**
+ * Removes a property from the section.
+ * @param id
+ * The property's id.
+ */
+ public detachProperty(id: string): void;
+
+ /**
+ * Removes a property from the section.
+ * @param asm
+ * The property's assembler.
+ */
+ public detachProperty(asm: PropertyAssembler): void;
+ public detachProperty(obj: string | PropertyAssembler): void {
+ if(!this.includesProperty(obj)) {
+ return;
+ }
+ if(typeof obj === "string") {
+ obj = this.properties.get(obj)!;
+ }
+ // Detach property
+ let id = obj.property.id;
+ this.accessor.properties.delete(id);
+ this._propertyAssemblers.delete(id);
+ // Detach parent
+ obj.detachFromParent();
+ }
+
+ /**
+ * Tests if the section includes a property.
+ * @param id
+ * The property's id.
+ * @returns
+ * True if the section includes the property, false otherwise.
+ */
+ public includesProperty(id: string): boolean;
+
+ /**
+ * Tests if the section includes a property.
+ * @param asm
+ * The property's assembler.
+ * @returns
+ * True if the section includes the property, false otherwise.
+ */
+ public includesProperty(asm: PropertyAssembler): boolean;
+ public includesProperty(obj: string | PropertyAssembler): boolean;
+ public includesProperty(obj: string | PropertyAssembler): boolean {
+ let properties = this.accessor.properties;
+ // If string
+ if(typeof obj === "string") {
+ return properties.has(obj);
+ }
+ // If property
+ let id = obj.property.id;
+ if(!properties.has(id)) {
+ return false;
+ }
+ let prop = properties.get(id)!;
+ if(prop.instance !== obj.property.instance) {
+ return false;
+ }
+ return true;
+ }
+
+}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Page/Section/SectionLayout.ts b/src/cti_authoring_tool/src/assets/scripts/Page/Section/SectionLayout.ts
new file mode 100644
index 0000000..3a6c95e
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/Page/Section/SectionLayout.ts
@@ -0,0 +1,13 @@
+export interface SectionLayout {
+
+ /**
+ * The number of rows in the section.
+ */
+ readonly rows: number,
+
+ /**
+ * The number of columns in the section.
+ */
+ readonly cols: number
+
+}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Page/Section/SectionParameters.ts b/src/cti_authoring_tool/src/assets/scripts/Page/Section/SectionParameters.ts
new file mode 100644
index 0000000..15d8c92
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/Page/Section/SectionParameters.ts
@@ -0,0 +1,35 @@
+export type SectionParameters = {
+
+ /**
+ * The section's id.
+ */
+ id: string;
+
+ /**
+ * The section's name.
+ */
+ name?: string | null;
+
+ /**
+ * The section's export path.
+ */
+ path?: string | null;
+
+ /**
+ * The section's layout.
+ */
+ layout: {
+
+ /**
+ * The number of rows in the section.
+ */
+ rows: number,
+
+ /**
+ * The number of columns in the section.
+ */
+ cols: number
+
+ }
+
+}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Page/Section/index.ts b/src/cti_authoring_tool/src/assets/scripts/Page/Section/index.ts
new file mode 100644
index 0000000..61dc1ae
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/Page/Section/index.ts
@@ -0,0 +1,3 @@
+export * from "./Section";
+export * from "./SectionAssembler";
+export * from "./SectionParameters";
\ No newline at end of file
diff --git a/src/cti_authoring_tool/src/assets/scripts/Page/index.ts b/src/cti_authoring_tool/src/assets/scripts/Page/index.ts
new file mode 100644
index 0000000..e286f98
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/Page/index.ts
@@ -0,0 +1,8 @@
+export * from "./Property";
+export * from "./Section";
+export * from "./Page";
+export * from "./PageElement";
+export * from "./PageAssembler";
+export * from "./PageParameters";
+export * from "./Plugins/Plugin";
+export * from "./Plugins/PluginConfiguration";
diff --git a/src/cti_authoring_tool/src/assets/scripts/Commands/PageCommand.ts b/src/cti_authoring_tool/src/assets/scripts/PageEditor/Commands/PageCommand.ts
similarity index 100%
rename from src/cti_authoring_tool/src/assets/scripts/Commands/PageCommand.ts
rename to src/cti_authoring_tool/src/assets/scripts/PageEditor/Commands/PageCommand.ts
diff --git a/src/cti_authoring_tool/src/assets/scripts/Commands/PageCommands/ComplexTablePropertySetRowCollapse.ts b/src/cti_authoring_tool/src/assets/scripts/PageEditor/Commands/Property/ComplexTable/CollapseComplexTablePropertyRow.ts
similarity index 82%
rename from src/cti_authoring_tool/src/assets/scripts/Commands/PageCommands/ComplexTablePropertySetRowCollapse.ts
rename to src/cti_authoring_tool/src/assets/scripts/PageEditor/Commands/Property/ComplexTable/CollapseComplexTablePropertyRow.ts
index 1743a3f..aca452a 100644
--- a/src/cti_authoring_tool/src/assets/scripts/Commands/PageCommands/ComplexTablePropertySetRowCollapse.ts
+++ b/src/cti_authoring_tool/src/assets/scripts/PageEditor/Commands/Property/ComplexTable/CollapseComplexTablePropertyRow.ts
@@ -1,7 +1,7 @@
-import { PageCommand } from "../PageCommand";
-import { ComplexTableProperty } from "../../Page/Property";
+import { PageCommand } from "../../PageCommand";
+import { ComplexTableProperty } from "@/assets/scripts/Page";
-export class ComplexTablePropertySetRowCollapse extends PageCommand {
+export class CollapseComplexTablePropertyRow extends PageCommand {
/**
* The table property to modify.
@@ -31,10 +31,10 @@ export class ComplexTablePropertySetRowCollapse extends PageCommand {
* @param row
* The row's id.
* @param collapse
- * True to collapse, false to uncollapse.
+ * True to collapse, false to expand.
*/
constructor(property: ComplexTableProperty, id: string, collapse: boolean) {
- super(property.getPageInstance());
+ super(property.rootInstance);
if(!property.value.has(id)) {
throw new Error(`Row '${ id }' does not exist in '${ property.id }'.`);
}
diff --git a/src/cti_authoring_tool/src/assets/scripts/PageEditor/Commands/Property/ComplexTable/ComplexTable.ts b/src/cti_authoring_tool/src/assets/scripts/PageEditor/Commands/Property/ComplexTable/ComplexTable.ts
new file mode 100644
index 0000000..0fec218
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/PageEditor/Commands/Property/ComplexTable/ComplexTable.ts
@@ -0,0 +1,7 @@
+import { PageCommand } from "../../PageCommand";
+import { ComplexTableProperty } from "@/assets/scripts/Page";
+import { CollapseComplexTablePropertyRow } from "./CollapseComplexTablePropertyRow";
+
+export function collapseComplexTablePropertyRow(prop: ComplexTableProperty, id: string, collapse: boolean): PageCommand {
+ return new CollapseComplexTablePropertyRow(prop, id, collapse)
+}
diff --git a/src/cti_authoring_tool/src/assets/scripts/PageEditor/Commands/Property/DateTime/DateTime.ts b/src/cti_authoring_tool/src/assets/scripts/PageEditor/Commands/Property/DateTime/DateTime.ts
new file mode 100644
index 0000000..d360454
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/PageEditor/Commands/Property/DateTime/DateTime.ts
@@ -0,0 +1,27 @@
+import { PageCommand } from "../../PageCommand";
+import { DateTimeProperty } from "@/assets/scripts/Page";
+import { SetDateTimeProperty } from "./SetDateTimeProperty";
+
+/**
+ * Sets a datetime property's value.
+ * @param prop
+ * The datetime property.
+ * @param value
+ * The datetime property's new value.
+ * @returns
+ * A command that represents the action.
+ */
+export function setDateTimeProperty(prop: DateTimeProperty, value: Date | null): PageCommand {
+ return new SetDateTimeProperty(prop, value);
+}
+
+/**
+ * Clears a datetime property's value.
+ * @param prop
+ * The datetime property.
+ * @returns
+ * A command that represents the action.
+ */
+export function clearDateTimeProperty(prop: DateTimeProperty): PageCommand {
+ return new SetDateTimeProperty(prop, null);
+}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Commands/PageCommands/DateTimePropertySet.ts b/src/cti_authoring_tool/src/assets/scripts/PageEditor/Commands/Property/DateTime/SetDateTimeProperty.ts
similarity index 74%
rename from src/cti_authoring_tool/src/assets/scripts/Commands/PageCommands/DateTimePropertySet.ts
rename to src/cti_authoring_tool/src/assets/scripts/PageEditor/Commands/Property/DateTime/SetDateTimeProperty.ts
index 0a9de0a..87d7aeb 100644
--- a/src/cti_authoring_tool/src/assets/scripts/Commands/PageCommands/DateTimePropertySet.ts
+++ b/src/cti_authoring_tool/src/assets/scripts/PageEditor/Commands/Property/DateTime/SetDateTimeProperty.ts
@@ -1,7 +1,7 @@
-import { PageCommand } from "../PageCommand";
-import { DateTimeProperty } from "../../Page/Property";
+import { PageCommand } from "../../PageCommand";
+import { DateTimeProperty } from "@/assets/scripts/Page";
-export class DateTimePropertySet extends PageCommand {
+export class SetDateTimeProperty extends PageCommand {
/**
* The property to modify.
@@ -27,7 +27,7 @@ export class DateTimePropertySet extends PageCommand {
* The property's new value.
*/
constructor(property: DateTimeProperty, value: Date | null) {
- super(property.getPageInstance());
+ super(property.rootInstance);
this._property = property;
this._lastValue = property.value;
this._nextValue = value;
@@ -40,7 +40,7 @@ export class DateTimePropertySet extends PageCommand {
* True if the command should be recorded, false otherwise.
*/
public execute(): boolean {
- this._property.setValue(this._nextValue);
+ this._property.value = this._nextValue;
return true;
}
@@ -48,7 +48,7 @@ export class DateTimePropertySet extends PageCommand {
* Undoes the page command.
*/
public undo() {
- this._property.setValue(this._lastValue);
+ this._property.value = this._lastValue;
}
}
diff --git a/src/cti_authoring_tool/src/assets/scripts/PageEditor/Commands/Property/Enum/Enum.ts b/src/cti_authoring_tool/src/assets/scripts/PageEditor/Commands/Property/Enum/Enum.ts
new file mode 100644
index 0000000..aec4a08
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/PageEditor/Commands/Property/Enum/Enum.ts
@@ -0,0 +1,27 @@
+import { PageCommand } from "../../PageCommand";
+import { EnumProperty } from "@/assets/scripts/Page";
+import { SetEnumProperty } from "./SetEnumProperty";
+
+/**
+ * Sets a enum property's value.
+ * @param prop
+ * The enum property.
+ * @param value
+ * The enum property's new value.
+ * @returns
+ * A command that represents the action.
+ */
+export function setEnumProperty(prop: EnumProperty, value: string | null): PageCommand {
+ return new SetEnumProperty(prop, value);
+}
+
+/**
+ * Clears a enum property's value.
+ * @param prop
+ * The enum property.
+ * @returns
+ * A command that represents the action.
+ */
+export function clearEnumProperty(prop: EnumProperty): PageCommand {
+ return new SetEnumProperty(prop, null);
+}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Commands/PageCommands/EnumPropertySet.ts b/src/cti_authoring_tool/src/assets/scripts/PageEditor/Commands/Property/Enum/SetEnumProperty.ts
similarity index 75%
rename from src/cti_authoring_tool/src/assets/scripts/Commands/PageCommands/EnumPropertySet.ts
rename to src/cti_authoring_tool/src/assets/scripts/PageEditor/Commands/Property/Enum/SetEnumProperty.ts
index dc38be0..5c7a2ff 100644
--- a/src/cti_authoring_tool/src/assets/scripts/Commands/PageCommands/EnumPropertySet.ts
+++ b/src/cti_authoring_tool/src/assets/scripts/PageEditor/Commands/Property/Enum/SetEnumProperty.ts
@@ -1,7 +1,7 @@
-import { PageCommand } from "../PageCommand";
-import { EnumProperty } from "../../Page/Property";
+import { PageCommand } from "../../PageCommand";
+import { EnumProperty } from "@/assets/scripts/Page";
-export class EnumPropertySet extends PageCommand {
+export class SetEnumProperty extends PageCommand {
/**
* The property to modify.
@@ -27,7 +27,7 @@ export class EnumPropertySet extends PageCommand {
* The property's new value.
*/
constructor(property: EnumProperty, value: string | null) {
- super(property.getPageInstance());
+ super(property.rootInstance);
this._property = property;
this._lastValue = property.value;
this._nextValue = value;
@@ -40,7 +40,7 @@ export class EnumPropertySet extends PageCommand {
* True if the command should be recorded, false otherwise.
*/
public execute(): boolean {
- this._property.setValue(this._nextValue);
+ this._property.value = this._nextValue;
return true;
}
@@ -48,7 +48,7 @@ export class EnumPropertySet extends PageCommand {
* Undoes the page command.
*/
public undo() {
- this._property.setValue(this._lastValue);
+ this._property.value = this._lastValue;
}
}
diff --git a/src/cti_authoring_tool/src/assets/scripts/PageEditor/Commands/Property/Number/Number.ts b/src/cti_authoring_tool/src/assets/scripts/PageEditor/Commands/Property/Number/Number.ts
new file mode 100644
index 0000000..3a1b39d
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/PageEditor/Commands/Property/Number/Number.ts
@@ -0,0 +1,27 @@
+import { PageCommand } from "../../PageCommand";
+import { NumberProperty } from "@/assets/scripts/Page";
+import { SetNumberProperty } from "./SetNumberProperty";
+
+/**
+ * Sets a number property's value.
+ * @param prop
+ * The number property.
+ * @param value
+ * The number property's new value.
+ * @returns
+ * A command that represents the action.
+ */
+export function setNumberProperty(prop: NumberProperty, value: number | null): PageCommand {
+ return new SetNumberProperty(prop, value);
+}
+
+/**
+ * Clears a number property's value.
+ * @param prop
+ * The number property.
+ * @returns
+ * A command that represents the action.
+ */
+export function clearNumberProperty(prop: NumberProperty): PageCommand {
+ return new SetNumberProperty(prop, null);
+}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Commands/PageCommands/NumberPropertySet.ts b/src/cti_authoring_tool/src/assets/scripts/PageEditor/Commands/Property/Number/SetNumberProperty.ts
similarity index 75%
rename from src/cti_authoring_tool/src/assets/scripts/Commands/PageCommands/NumberPropertySet.ts
rename to src/cti_authoring_tool/src/assets/scripts/PageEditor/Commands/Property/Number/SetNumberProperty.ts
index ce77321..8fa7c74 100644
--- a/src/cti_authoring_tool/src/assets/scripts/Commands/PageCommands/NumberPropertySet.ts
+++ b/src/cti_authoring_tool/src/assets/scripts/PageEditor/Commands/Property/Number/SetNumberProperty.ts
@@ -1,7 +1,7 @@
-import { PageCommand } from "../PageCommand";
-import { NumberProperty } from "../../Page/Property";
+import { PageCommand } from "../../PageCommand";
+import { NumberProperty } from "@/assets/scripts/Page";
-export class NumberPropertySet extends PageCommand {
+export class SetNumberProperty extends PageCommand {
/**
* The property to modify.
@@ -27,7 +27,7 @@ export class NumberPropertySet extends PageCommand {
* The property's new value.
*/
constructor(property: NumberProperty, value: number | null) {
- super(property.getPageInstance());
+ super(property.rootInstance);
this._property = property;
this._lastValue = property.value;
this._nextValue = value;
@@ -40,7 +40,7 @@ export class NumberPropertySet extends PageCommand {
* True if the command should be recorded, false otherwise.
*/
public execute(): boolean {
- this._property.setValue(this._nextValue);
+ this._property.value = this._nextValue;
return true;
}
@@ -48,7 +48,7 @@ export class NumberPropertySet extends PageCommand {
* Undoes the page command.
*/
public undo() {
- this._property.setValue(this._lastValue);
+ this._property.value = this._lastValue;
}
}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Commands/PageCommands/StringPropertySet.ts b/src/cti_authoring_tool/src/assets/scripts/PageEditor/Commands/Property/String/SetStringProperty.ts
similarity index 75%
rename from src/cti_authoring_tool/src/assets/scripts/Commands/PageCommands/StringPropertySet.ts
rename to src/cti_authoring_tool/src/assets/scripts/PageEditor/Commands/Property/String/SetStringProperty.ts
index b3e67a6..d8ef9ce 100644
--- a/src/cti_authoring_tool/src/assets/scripts/Commands/PageCommands/StringPropertySet.ts
+++ b/src/cti_authoring_tool/src/assets/scripts/PageEditor/Commands/Property/String/SetStringProperty.ts
@@ -1,7 +1,7 @@
-import { PageCommand } from "../PageCommand";
-import { StringProperty } from "../../Page/Property";
+import { PageCommand } from "../../PageCommand";
+import { StringProperty } from "@/assets/scripts/Page";
-export class StringPropertySet extends PageCommand {
+export class SetStringProperty extends PageCommand {
/**
* The property to modify.
@@ -27,7 +27,7 @@ export class StringPropertySet extends PageCommand {
* The property's new value.
*/
constructor(property: StringProperty, value: string | null) {
- super(property.getPageInstance());
+ super(property.rootInstance);
this._property = property;
this._lastValue = property.value;
this._nextValue = value;
@@ -40,7 +40,7 @@ export class StringPropertySet extends PageCommand {
* True if the command should be recorded, false otherwise.
*/
public execute(): boolean {
- this._property.setValue(this._nextValue);
+ this._property.value = this._nextValue;
return true;
}
@@ -48,7 +48,7 @@ export class StringPropertySet extends PageCommand {
* Undoes the page command.
*/
public undo() {
- this._property.setValue(this._lastValue);
+ this._property.value = this._lastValue;
}
}
diff --git a/src/cti_authoring_tool/src/assets/scripts/PageEditor/Commands/Property/String/String.ts b/src/cti_authoring_tool/src/assets/scripts/PageEditor/Commands/Property/String/String.ts
new file mode 100644
index 0000000..a803c11
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/PageEditor/Commands/Property/String/String.ts
@@ -0,0 +1,27 @@
+import { PageCommand } from "../../PageCommand";
+import { StringProperty } from "@/assets/scripts/Page";
+import { SetStringProperty } from "./SetStringProperty";
+
+/**
+ * Sets a string property's value.
+ * @param prop
+ * The string property.
+ * @param value
+ * The string property's new value.
+ * @returns
+ * A command that represents the action.
+ */
+export function setStringProperty(prop: StringProperty, value: string | null): PageCommand {
+ return new SetStringProperty(prop, value);
+}
+
+/**
+ * Clears a string property's value.
+ * @param prop
+ * The string property.
+ * @returns
+ * A command that represents the action.
+ */
+export function clearStringProperty(prop: StringProperty): PageCommand {
+ return new SetStringProperty(prop, null);
+}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Commands/PageCommands/TabularPropertyCreateRow.ts b/src/cti_authoring_tool/src/assets/scripts/PageEditor/Commands/Property/Tabular/CreateTabularPropertyRow.ts
similarity index 73%
rename from src/cti_authoring_tool/src/assets/scripts/Commands/PageCommands/TabularPropertyCreateRow.ts
rename to src/cti_authoring_tool/src/assets/scripts/PageEditor/Commands/Property/Tabular/CreateTabularPropertyRow.ts
index c932aef..7576200 100644
--- a/src/cti_authoring_tool/src/assets/scripts/Commands/PageCommands/TabularPropertyCreateRow.ts
+++ b/src/cti_authoring_tool/src/assets/scripts/PageEditor/Commands/Property/Tabular/CreateTabularPropertyRow.ts
@@ -1,8 +1,7 @@
-import { PageCommand } from "../PageCommand";
-import { AtomicProperty } from "../../Page/Property";
-import { TabularProperty } from "../../Page/Property/TabularProperty/TabularProperty";
+import { PageCommand } from "../../PageCommand";
+import { AtomicProperty, TabularProperty } from "@/assets/scripts/Page";
-export class TabularPropertyCreateRow extends PageCommand {
+export class CreateTabularPropertyRow extends PageCommand {
/**
* The tabular property to modify.
@@ -21,7 +20,7 @@ export class TabularPropertyCreateRow extends PageCommand {
* The tabular property.
*/
constructor(property: TabularProperty) {
- super(property.getPageInstance());
+ super(property.rootInstance);
this._property = property;
this._row = property.createRow();
}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Commands/PageCommands/TabularPropertyDeleteRow.ts b/src/cti_authoring_tool/src/assets/scripts/PageEditor/Commands/Property/Tabular/DeleteTabularPropertyRow.ts
similarity index 73%
rename from src/cti_authoring_tool/src/assets/scripts/Commands/PageCommands/TabularPropertyDeleteRow.ts
rename to src/cti_authoring_tool/src/assets/scripts/PageEditor/Commands/Property/Tabular/DeleteTabularPropertyRow.ts
index 566aa4e..2dc192d 100644
--- a/src/cti_authoring_tool/src/assets/scripts/Commands/PageCommands/TabularPropertyDeleteRow.ts
+++ b/src/cti_authoring_tool/src/assets/scripts/PageEditor/Commands/Property/Tabular/DeleteTabularPropertyRow.ts
@@ -1,8 +1,7 @@
-import { PageCommand } from "../PageCommand";
-import { AtomicProperty } from "../../Page/Property";
-import { TabularProperty } from "../../Page/Property/TabularProperty/TabularProperty";
+import { PageCommand } from "../../PageCommand";
+import { AtomicProperty, TabularProperty } from "@/assets/scripts/Page";
-export class TabularPropertyDeleteRow extends PageCommand {
+export class DeleteTabularPropertyRow extends PageCommand {
/**
* The tabular property to modify.
@@ -28,13 +27,13 @@ export class TabularPropertyDeleteRow extends PageCommand {
* The row's id.
*/
constructor(property: TabularProperty, id: string) {
- super(property.getPageInstance());
- if(property.getIndex(id) === -1) {
+ super(property.rootInstance);
+ if(property.getRowIndex(id) === -1) {
throw new Error(`Table row '${ id }' does not exist in '${ property.id }'.`);
}
this._property = property;
this._row = property.getRow(id)!;
- this._index = property.getIndex(id)!;
+ this._index = property.getRowIndex(id)!;
}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Commands/PageCommands/TabularPropertyMoveRow.ts b/src/cti_authoring_tool/src/assets/scripts/PageEditor/Commands/Property/Tabular/MoveTabularPropertyRow.ts
similarity index 76%
rename from src/cti_authoring_tool/src/assets/scripts/Commands/PageCommands/TabularPropertyMoveRow.ts
rename to src/cti_authoring_tool/src/assets/scripts/PageEditor/Commands/Property/Tabular/MoveTabularPropertyRow.ts
index 64b2ca9..051f83e 100644
--- a/src/cti_authoring_tool/src/assets/scripts/Commands/PageCommands/TabularPropertyMoveRow.ts
+++ b/src/cti_authoring_tool/src/assets/scripts/PageEditor/Commands/Property/Tabular/MoveTabularPropertyRow.ts
@@ -1,7 +1,7 @@
-import { PageCommand } from "../PageCommand";
-import { TabularProperty } from "../../Page/Property/TabularProperty/TabularProperty";
+import { PageCommand } from "../../PageCommand";
+import { TabularProperty } from "@/assets/scripts/Page";
-export class TabularPropertyMoveRow extends PageCommand {
+export class MoveTabularPropertyRow extends PageCommand {
/**
* The tabular property to modify.
@@ -29,12 +29,12 @@ export class TabularPropertyMoveRow extends PageCommand {
* The row's new index.
*/
constructor(property: TabularProperty, id: string, dst: number) {
- super(property.getPageInstance());
- if(property.getIndex(id) === -1) {
+ super(property.rootInstance);
+ if(property.getRowIndex(id) === -1) {
throw new Error(`Table row '${ id }' does not exist in '${ property.id }'.`);
}
this._property = property;
- this._src = this._property.getIndex(id);
+ this._src = this._property.getRowIndex(id);
this._dst = dst;
}
diff --git a/src/cti_authoring_tool/src/assets/scripts/Commands/PageCommands/TabularPropertyReorder.ts b/src/cti_authoring_tool/src/assets/scripts/PageEditor/Commands/Property/Tabular/ReorderTabularProperty.ts
similarity index 79%
rename from src/cti_authoring_tool/src/assets/scripts/Commands/PageCommands/TabularPropertyReorder.ts
rename to src/cti_authoring_tool/src/assets/scripts/PageEditor/Commands/Property/Tabular/ReorderTabularProperty.ts
index 25b6305..186610b 100644
--- a/src/cti_authoring_tool/src/assets/scripts/Commands/PageCommands/TabularPropertyReorder.ts
+++ b/src/cti_authoring_tool/src/assets/scripts/PageEditor/Commands/Property/Tabular/ReorderTabularProperty.ts
@@ -1,7 +1,7 @@
-import { PageCommand } from "../PageCommand";
-import { ColumnSnapshot, Sort, TabularProperty } from "../../Page/Property";
+import { PageCommand } from "../../PageCommand";
+import { ColumnSnapshot, Sort, TabularProperty } from "@/assets/scripts/Page";
-export class TabularPropertyReorder extends PageCommand {
+export class ReorderTabularProperty extends PageCommand {
/**
* The tabular property to modify.
@@ -24,13 +24,13 @@ export class TabularPropertyReorder extends PageCommand {
* @param property
* The tabular property.
* @param id
- * The column's id.
+ * The id of the column to order on.
* @param sort
* The column's new sort order.
*/
constructor(property: TabularProperty, id: string, sort: Sort) {
- super(property.getPageInstance());
- if(!property.properties.find(o => o.id === id)) {
+ super(property.rootInstance);
+ if(!property.columnState.find(o => o.id === id)) {
throw new Error(`Table column '${ id }' does not exist in '${ property.id }'.`);
}
this._property = property;
diff --git a/src/cti_authoring_tool/src/assets/scripts/PageEditor/Commands/Property/Tabular/Tabular.ts b/src/cti_authoring_tool/src/assets/scripts/PageEditor/Commands/Property/Tabular/Tabular.ts
new file mode 100644
index 0000000..d6d8a4a
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/PageEditor/Commands/Property/Tabular/Tabular.ts
@@ -0,0 +1,60 @@
+import { PageCommand } from "../../PageCommand";
+import { Sort, TabularProperty } from "@/assets/scripts/Page";
+import { MoveTabularPropertyRow } from "./MoveTabularPropertyRow";
+import { ReorderTabularProperty } from "./ReorderTabularProperty";
+import { CreateTabularPropertyRow } from "./CreateTabularPropertyRow";
+import { DeleteTabularPropertyRow } from "./DeleteTabularPropertyRow";
+
+/**
+ * Adds a new row to a tabular property.
+ * @param prop
+ * The tabular property.
+ * @returns
+ * A command that represents the action.
+ */
+export function createTabularPropertyRow(prop: TabularProperty): PageCommand {
+ return new CreateTabularPropertyRow(prop);
+}
+
+/**
+ * Deletes a row from a tabular property.
+ * @param prop
+ * The tabular property.
+ * @param id
+ * The row's id.
+ * @returns
+ * A command that represents the action.
+ */
+export function deleteTabularPropertyRow(prop: TabularProperty, id: string): PageCommand {
+ return new DeleteTabularPropertyRow(prop, id);
+}
+
+/**
+ * Moves a row to a specific location within a tabular property.
+ * @param prop
+ * The tabular property.
+ * @param id
+ * The row's id.
+ * @param dst
+ * The row's new index.
+ * @returns
+ * A command that represents the action.
+ */
+export function moveTabularPropertyRow(prop: TabularProperty, id: string, dst: number): PageCommand {
+ return new MoveTabularPropertyRow(prop, id, dst)
+}
+
+/**
+ * Reorders a tabular property.
+ * @param prop
+ * The tabular property.
+ * @param id
+ * The id of the column to order on.
+ * @param sort
+ * The column's sort order.
+ * @returns
+ * A command that represents the action.
+ */
+export function reorderTabularProperty(prop: TabularProperty, id: string, sort: Sort): PageCommand {
+ return new ReorderTabularProperty(prop, id, sort)
+}
diff --git a/src/cti_authoring_tool/src/assets/scripts/PageEditor/Commands/Property/index.ts b/src/cti_authoring_tool/src/assets/scripts/PageEditor/Commands/Property/index.ts
new file mode 100644
index 0000000..c158419
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/PageEditor/Commands/Property/index.ts
@@ -0,0 +1,6 @@
+export * from "./ComplexTable/ComplexTable";
+export * from "./DateTime/DateTime";
+export * from "./Enum/Enum"
+export * from "./Number/Number";
+export * from "./String/String";
+export * from "./Tabular/Tabular";
\ No newline at end of file
diff --git a/src/cti_authoring_tool/src/assets/scripts/PageEditor/Commands/index.ts b/src/cti_authoring_tool/src/assets/scripts/PageEditor/Commands/index.ts
new file mode 100644
index 0000000..683b223
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/PageEditor/Commands/index.ts
@@ -0,0 +1,2 @@
+export * from "./Property"
+export * from "./PageCommand";
\ No newline at end of file
diff --git a/src/cti_authoring_tool/src/assets/scripts/Page/PageEditor.ts b/src/cti_authoring_tool/src/assets/scripts/PageEditor/PageEditor.ts
similarity index 54%
rename from src/cti_authoring_tool/src/assets/scripts/Page/PageEditor.ts
rename to src/cti_authoring_tool/src/assets/scripts/PageEditor/PageEditor.ts
index fd9654d..2cd073c 100644
--- a/src/cti_authoring_tool/src/assets/scripts/Page/PageEditor.ts
+++ b/src/cti_authoring_tool/src/assets/scripts/PageEditor/PageEditor.ts
@@ -1,18 +1,37 @@
-import { Page } from "./Page";
-import { PageCommand } from "@/assets/scripts/Commands/PageCommand";
-import { PageTemplate } from "../AppConfiguration";
+import * as PageImporter from "./PageImporter";
+import * as PageExporter from "./PageExporter";
+import { version } from "@/../package.json";
+import { PageCommand } from "./Commands/PageCommand";
+import { Page, Property } from "../Page";
export class PageEditor {
+ /**
+ * The phantom page editor.
+ */
+ public static Phantom: PageEditor = new this(
+ "", [], new Page({ id: "phantom_template" })
+ );
+
/**
* The editor's id.
*/
- public id: string;
+ public readonly id: string;
+
+ /**
+ * The page's keys.
+ */
+ public readonly keys: ReadonlyArray;
+
+ /**
+ * The page's template name.
+ */
+ public readonly template: string;
/**
* The editor's page.
*/
- public page: Page;
+ public readonly page: Page;
/**
* The editor's undo stack.
@@ -24,28 +43,56 @@ export class PageEditor {
*/
private _redoStack: PageCommand[];
+
/**
- * The phantom page editor.
+ * The page's name.
*/
- public static Phantom: PageEditor = new this(
- new Page({
- id: "phantom_template",
- name: "Phantom Template",
- sections: []
- })
- );
+ public get name(): string {
+ let name = this.keys
+ .map(o => o.toString())
+ .filter(o => o !== undefined)
+ .join(" - ");
+ return name || `Untitled ${ this.template }`;
+ };
/**
* Creates a new {@link PageEditor}.
+ * @param template
+ * The page's template name.
+ * @param keys
+ * The page's keys.
* @param page
- * The page to edit.
+ * The page.
*/
- private constructor(page: Page) {
+ private constructor(template: string, keys: string[], page: Page) {
+
+ // Initialize state
this.id = page.instance;
this.page = page;
+ this.template = template;
this._undoStack = [];
this._redoStack = [];
+
+ // Resolve keys
+ let _keys = [];
+ for(let key of keys) {
+ let [s, p] = key.split(/\./g);
+ let property, section;
+ if(section = page.sections.get(s)) {
+ property = section.properties.get(p)
+ }
+ if(property) {
+ _keys.push(property);
+ }
+ }
+ this.keys = _keys;
+
+ // Subscribe to execute event
+ this.page.on("execute", (command: PageCommand) => {
+ this.execute(command);
+ });
+
}
@@ -128,22 +175,38 @@ export class PageEditor {
* @returns
* The page's editor.
*/
- public static createNew(template: PageTemplate): PageEditor {
- return new this(new Page(template));
+ public static createNew(template: PageImporter.PageTemplate): PageEditor {
+ return new this(template.name, template.keys, PageImporter.newPage(template).page);
}
/**
* Deserializes a page export.
- * @param file
- * The page export.
* @param template
* The page's template.
+ * @param value
+ * The page's values.
* @returns
* The page's editor.
*/
- public static fromFile(template: PageTemplate, file: string): PageEditor {
- // Resolve template and pass serialized page
- return new this(new Page(template));
+ public static fromFile(template: PageImporter.PageTemplate, value: any): PageEditor {
+ return new this(template.name, template.keys, PageImporter.newPage(template, undefined, value).page);
+ }
+
+ /**
+ * Exports the page as a text file.
+ * @returns
+ * The serialized page.
+ */
+ public toFile(): string {
+ return JSON.stringify({
+ ...PageExporter.serialize(this.page).toObject(),
+ __document: {
+ authoring_tool_version: version,
+ template_name: this.template,
+ template_version: "0.1.0",
+ template_identifier: this.page.id
+ }
+ }, null, 4);
}
}
diff --git a/src/cti_authoring_tool/src/assets/scripts/PageEditor/PageExporter/Nodes/AtomicNode.ts b/src/cti_authoring_tool/src/assets/scripts/PageEditor/PageExporter/Nodes/AtomicNode.ts
new file mode 100644
index 0000000..84b4453
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/PageEditor/PageExporter/Nodes/AtomicNode.ts
@@ -0,0 +1,32 @@
+import { ExportNode } from "./ExportNode";
+import { Value } from "./Value";
+
+export class AtomicNode extends ExportNode {
+
+ /**
+ * The node's value.
+ */
+ public value: Value
+
+
+ /**
+ * Creates a new {@link AtomicNode}.
+ * @param value
+ * The node's value.
+ */
+ constructor(value: Value) {
+ super();
+ this.value = value;
+ }
+
+
+ /**
+ * Serializes the node to an object.
+ * @returns
+ * The object.
+ */
+ public override toObject(): Value {
+ return this.value;
+ }
+
+}
diff --git a/src/cti_authoring_tool/src/assets/scripts/PageEditor/PageExporter/Nodes/ExportNode.ts b/src/cti_authoring_tool/src/assets/scripts/PageEditor/PageExporter/Nodes/ExportNode.ts
new file mode 100644
index 0000000..eafa543
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/PageEditor/PageExporter/Nodes/ExportNode.ts
@@ -0,0 +1,20 @@
+import { MapNode } from "./MapNode";
+
+export abstract class ExportNode extends Map{
+
+ /**
+ * Creates a new {@link ExportNode}.
+ */
+ constructor() {
+ super();
+ }
+
+
+ /**
+ * Serializes the node to an object.
+ * @returns
+ * The object.
+ */
+ public abstract toObject(): E;
+
+}
diff --git a/src/cti_authoring_tool/src/assets/scripts/PageEditor/PageExporter/Nodes/MapNode.ts b/src/cti_authoring_tool/src/assets/scripts/PageEditor/PageExporter/Nodes/MapNode.ts
new file mode 100644
index 0000000..bb828c9
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/PageEditor/PageExporter/Nodes/MapNode.ts
@@ -0,0 +1,8 @@
+import { AtomicNode } from "./AtomicNode";
+import { ObjectMapNode } from "./ObjectMapNode";
+import { ObjectArrayNode } from "./ObjectArrayNode";
+
+/**
+ * Map Node type
+ */
+export type MapNode = ObjectMapNode | ObjectArrayNode | AtomicNode;
diff --git a/src/cti_authoring_tool/src/assets/scripts/PageEditor/PageExporter/Nodes/ObjectArrayNode.ts b/src/cti_authoring_tool/src/assets/scripts/PageEditor/PageExporter/Nodes/ObjectArrayNode.ts
new file mode 100644
index 0000000..7b9e658
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/PageEditor/PageExporter/Nodes/ObjectArrayNode.ts
@@ -0,0 +1,46 @@
+import * as Crypto from "@/assets/scripts/Utilities";
+import { ExportNode } from "./ExportNode";
+import { Value } from "./Value";
+import { MapNode } from "./MapNode";
+
+export class ObjectArrayNode extends ExportNode<(Object | Value)[]> {
+
+ /**
+ * Creates a new {@link ObjectArrayNode}.
+ */
+ constructor() {
+ super();
+ }
+
+
+ /**
+ * Appends a new {@link MapNode} to the end of the array.
+ * @returns
+ * The {@link MapNode}'s assigned index.
+ */
+ public push(node: MapNode): string {
+ // Generate index
+ let index;
+ do {
+ index = Crypto.randomUUID()
+ } while(this.has(index));
+ // Assign node
+ this.set(index, node);
+ // Return index
+ return index;
+ }
+
+ /**
+ * Serializes the node to an object.
+ * @returns
+ * The object.
+ */
+ public override toObject(): (Object | Value)[] {
+ let arr = [];
+ for(let value of this.values()) {
+ arr.push(value.toObject());
+ }
+ return arr;
+ }
+
+}
diff --git a/src/cti_authoring_tool/src/assets/scripts/PageEditor/PageExporter/Nodes/ObjectMapNode.ts b/src/cti_authoring_tool/src/assets/scripts/PageEditor/PageExporter/Nodes/ObjectMapNode.ts
new file mode 100644
index 0000000..dec5716
--- /dev/null
+++ b/src/cti_authoring_tool/src/assets/scripts/PageEditor/PageExporter/Nodes/ObjectMapNode.ts
@@ -0,0 +1,26 @@
+import { ExportNode } from "./ExportNode";
+
+export class ObjectMapNode extends ExportNode
diff --git a/src/cti_authoring_tool/src/components/Controls/Fields/EnumField.vue b/src/cti_authoring_tool/src/components/Controls/Fields/EnumField.vue
index a38968b..b04b086 100644
--- a/src/cti_authoring_tool/src/components/Controls/Fields/EnumField.vue
+++ b/src/cti_authoring_tool/src/components/Controls/Fields/EnumField.vue
@@ -41,11 +41,10 @@
diff --git a/src/cti_authoring_tool/src/components/Controls/Fields/OptionsList.vue b/src/cti_authoring_tool/src/components/Controls/Fields/OptionsList.vue
index d528c60..db81e04 100644
--- a/src/cti_authoring_tool/src/components/Controls/Fields/OptionsList.vue
+++ b/src/cti_authoring_tool/src/components/Controls/Fields/OptionsList.vue
@@ -24,7 +24,7 @@
diff --git a/src/cti_authoring_tool/src/components/Controls/PageEditorSection.vue b/src/cti_authoring_tool/src/components/Controls/PageEditorSection.vue
index c8ee039..f0ca256 100644
--- a/src/cti_authoring_tool/src/components/Controls/PageEditorSection.vue
+++ b/src/cti_authoring_tool/src/components/Controls/PageEditorSection.vue
@@ -1,6 +1,6 @@
-
+
{{ section.name }}
$emit('command', c)"
+ @execute="c => $emit('execute', c)"
/>