course-format-ts 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.idea/edu-format-ts.iml +10 -0
- package/.idea/inspectionProfiles/Project_Default.xml +28 -0
- package/.idea/misc.xml +4 -0
- package/.idea/modules.xml +8 -0
- package/.idea/vcs.xml +6 -0
- package/AGENTS.md +1 -0
- package/dist/courseFormat/AnswerPlaceholder.d.ts +37 -0
- package/dist/courseFormat/AnswerPlaceholder.js +101 -0
- package/dist/courseFormat/AnswerPlaceholderComparator.d.ts +4 -0
- package/dist/courseFormat/AnswerPlaceholderComparator.js +8 -0
- package/dist/courseFormat/AnswerPlaceholderDependency.d.ts +19 -0
- package/dist/courseFormat/AnswerPlaceholderDependency.js +91 -0
- package/dist/courseFormat/CheckFeedback.d.ts +20 -0
- package/dist/courseFormat/CheckFeedback.js +58 -0
- package/dist/courseFormat/CheckResult.d.ts +33 -0
- package/dist/courseFormat/CheckResult.js +58 -0
- package/dist/courseFormat/CheckResultSeverity.d.ts +7 -0
- package/dist/courseFormat/CheckResultSeverity.js +17 -0
- package/dist/courseFormat/CheckStatus.d.ts +5 -0
- package/dist/courseFormat/CheckStatus.js +9 -0
- package/dist/courseFormat/Course.d.ts +68 -0
- package/dist/courseFormat/Course.js +165 -0
- package/dist/courseFormat/CourseMode.d.ts +4 -0
- package/dist/courseFormat/CourseMode.js +8 -0
- package/dist/courseFormat/CourseVisibility.d.ts +4 -0
- package/dist/courseFormat/CourseVisibility.js +8 -0
- package/dist/courseFormat/CourseraCourse.d.ts +5 -0
- package/dist/courseFormat/CourseraCourse.js +15 -0
- package/dist/courseFormat/DescriptionFormat.d.ts +5 -0
- package/dist/courseFormat/DescriptionFormat.js +9 -0
- package/dist/courseFormat/EduCourse.d.ts +17 -0
- package/dist/courseFormat/EduCourse.js +42 -0
- package/dist/courseFormat/EduFile.d.ts +22 -0
- package/dist/courseFormat/EduFile.js +110 -0
- package/dist/courseFormat/EduFileErrorHighlightLevel.d.ts +5 -0
- package/dist/courseFormat/EduFileErrorHighlightLevel.js +9 -0
- package/dist/courseFormat/EduFormatNames.d.ts +75 -0
- package/dist/courseFormat/EduFormatNames.js +80 -0
- package/dist/courseFormat/EduTestInfo.d.ts +28 -0
- package/dist/courseFormat/EduTestInfo.js +68 -0
- package/dist/courseFormat/EduVersions.d.ts +2 -0
- package/dist/courseFormat/EduVersions.js +5 -0
- package/dist/courseFormat/FileContents.d.ts +36 -0
- package/dist/courseFormat/FileContents.js +67 -0
- package/dist/courseFormat/FileContentsFactory.d.ts +17 -0
- package/dist/courseFormat/FileContentsFactory.js +2 -0
- package/dist/courseFormat/FrameworkLesson.d.ts +9 -0
- package/dist/courseFormat/FrameworkLesson.js +28 -0
- package/dist/courseFormat/ItemContainer.d.ts +13 -0
- package/dist/courseFormat/ItemContainer.js +45 -0
- package/dist/courseFormat/JBAccountUserInfo.d.ts +9 -0
- package/dist/courseFormat/JBAccountUserInfo.js +20 -0
- package/dist/courseFormat/Language.d.ts +4 -0
- package/dist/courseFormat/Language.js +33 -0
- package/dist/courseFormat/Lesson.d.ts +20 -0
- package/dist/courseFormat/Lesson.js +56 -0
- package/dist/courseFormat/LessonContainer.d.ts +16 -0
- package/dist/courseFormat/LessonContainer.js +54 -0
- package/dist/courseFormat/PluginInfo.d.ts +7 -0
- package/dist/courseFormat/PluginInfo.js +15 -0
- package/dist/courseFormat/Section.d.ts +8 -0
- package/dist/courseFormat/Section.js +27 -0
- package/dist/courseFormat/StudyItem.d.ts +20 -0
- package/dist/courseFormat/StudyItem.js +47 -0
- package/dist/courseFormat/Tags.d.ts +16 -0
- package/dist/courseFormat/Tags.js +42 -0
- package/dist/courseFormat/TaskFile.d.ts +26 -0
- package/dist/courseFormat/TaskFile.js +72 -0
- package/dist/courseFormat/UserInfo.d.ts +3 -0
- package/dist/courseFormat/UserInfo.js +2 -0
- package/dist/courseFormat/Vendor.d.ts +7 -0
- package/dist/courseFormat/Vendor.js +14 -0
- package/dist/courseFormat/attempts/Attempt.d.ts +12 -0
- package/dist/courseFormat/attempts/Attempt.js +25 -0
- package/dist/courseFormat/attempts/AttemptBase.d.ts +9 -0
- package/dist/courseFormat/attempts/AttemptBase.js +28 -0
- package/dist/courseFormat/attempts/DataTaskAttempt.d.ts +6 -0
- package/dist/courseFormat/attempts/DataTaskAttempt.js +24 -0
- package/dist/courseFormat/attempts/Dataset.d.ts +12 -0
- package/dist/courseFormat/attempts/Dataset.js +21 -0
- package/dist/courseFormat/fileUtils.d.ts +5 -0
- package/dist/courseFormat/fileUtils.js +32 -0
- package/dist/courseFormat/hyperskill/HyperskillCourse.d.ts +13 -0
- package/dist/courseFormat/hyperskill/HyperskillCourse.js +25 -0
- package/dist/courseFormat/hyperskill/HyperskillProject.d.ts +10 -0
- package/dist/courseFormat/hyperskill/HyperskillProject.js +16 -0
- package/dist/courseFormat/hyperskill/HyperskillStage.d.ts +8 -0
- package/dist/courseFormat/hyperskill/HyperskillStage.js +20 -0
- package/dist/courseFormat/hyperskill/HyperskillTaskType.d.ts +4 -0
- package/dist/courseFormat/hyperskill/HyperskillTaskType.js +26 -0
- package/dist/courseFormat/hyperskill/HyperskillTopic.d.ts +5 -0
- package/dist/courseFormat/hyperskill/HyperskillTopic.js +11 -0
- package/dist/courseFormat/loggerUtils.d.ts +1 -0
- package/dist/courseFormat/loggerUtils.js +6 -0
- package/dist/courseFormat/stepik/StepikCourse.d.ts +5 -0
- package/dist/courseFormat/stepik/StepikCourse.js +15 -0
- package/dist/courseFormat/stepik/StepikLesson.d.ts +6 -0
- package/dist/courseFormat/stepik/StepikLesson.js +16 -0
- package/dist/courseFormat/tasks/AnswerTask.d.ts +8 -0
- package/dist/courseFormat/tasks/AnswerTask.js +11 -0
- package/dist/courseFormat/tasks/CodeTask.d.ts +12 -0
- package/dist/courseFormat/tasks/CodeTask.js +21 -0
- package/dist/courseFormat/tasks/DataTask.d.ts +18 -0
- package/dist/courseFormat/tasks/DataTask.js +32 -0
- package/dist/courseFormat/tasks/EduTask.d.ts +12 -0
- package/dist/courseFormat/tasks/EduTask.js +22 -0
- package/dist/courseFormat/tasks/IdeTask.d.ts +9 -0
- package/dist/courseFormat/tasks/IdeTask.js +14 -0
- package/dist/courseFormat/tasks/NumberTask.d.ts +9 -0
- package/dist/courseFormat/tasks/NumberTask.js +14 -0
- package/dist/courseFormat/tasks/OutputTask.d.ts +10 -0
- package/dist/courseFormat/tasks/OutputTask.js +18 -0
- package/dist/courseFormat/tasks/OutputTaskBase.d.ts +14 -0
- package/dist/courseFormat/tasks/OutputTaskBase.js +19 -0
- package/dist/courseFormat/tasks/RemoteEduTask.d.ts +9 -0
- package/dist/courseFormat/tasks/RemoteEduTask.js +15 -0
- package/dist/courseFormat/tasks/StringTask.d.ts +9 -0
- package/dist/courseFormat/tasks/StringTask.js +14 -0
- package/dist/courseFormat/tasks/TableTask.d.ts +17 -0
- package/dist/courseFormat/tasks/TableTask.js +43 -0
- package/dist/courseFormat/tasks/Task.d.ts +45 -0
- package/dist/courseFormat/tasks/Task.js +155 -0
- package/dist/courseFormat/tasks/TheoryTask.d.ts +10 -0
- package/dist/courseFormat/tasks/TheoryTask.js +15 -0
- package/dist/courseFormat/tasks/UnsupportedTask.d.ts +9 -0
- package/dist/courseFormat/tasks/UnsupportedTask.js +14 -0
- package/dist/courseFormat/tasks/choice/ChoiceOption.d.ts +10 -0
- package/dist/courseFormat/tasks/choice/ChoiceOption.js +33 -0
- package/dist/courseFormat/tasks/choice/ChoiceOptionStatus.d.ts +5 -0
- package/dist/courseFormat/tasks/choice/ChoiceOptionStatus.js +9 -0
- package/dist/courseFormat/tasks/choice/ChoiceTask.d.ts +23 -0
- package/dist/courseFormat/tasks/choice/ChoiceTask.js +47 -0
- package/dist/courseFormat/tasks/matching/MatchingTask.d.ts +10 -0
- package/dist/courseFormat/tasks/matching/MatchingTask.js +15 -0
- package/dist/courseFormat/tasks/matching/SortingBasedTask.d.ts +16 -0
- package/dist/courseFormat/tasks/matching/SortingBasedTask.js +50 -0
- package/dist/courseFormat/tasks/matching/SortingTask.d.ts +9 -0
- package/dist/courseFormat/tasks/matching/SortingTask.js +14 -0
- package/dist/courseFormat/uiMessages.d.ts +3 -0
- package/dist/courseFormat/uiMessages.js +14 -0
- package/dist/disk-loader.d.ts +4 -0
- package/dist/disk-loader.js +389 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.js +64 -0
- package/dist/loader.d.ts +7 -0
- package/dist/loader.js +435 -0
- package/dist/models.d.ts +49 -0
- package/dist/models.js +2 -0
- package/dist/zip-loader.d.ts +4 -0
- package/dist/zip-loader.js +431 -0
- package/example-course-project/course-info.yaml +15 -0
- package/example-course-project/lesson1/lesson-info.yaml +3 -0
- package/example-course-project/lesson1/lesson-remote-info.yaml +1 -0
- package/example-course-project/lesson1/task1/Task.txt +1 -0
- package/example-course-project/lesson1/task1/task-info.yaml +12 -0
- package/example-course-project/lesson1/task1/task-remote-info.yaml +1 -0
- package/example-course-project/lesson1/task1/task.md +47 -0
- package/example-course-project/lesson1/task1/tests/Tests.txt +0 -0
- package/example-course-project/lesson1/task2/Task.txt +1 -0
- package/example-course-project/lesson1/task2/task-info.yaml +12 -0
- package/example-course-project/lesson1/task2/task-remote-info.yaml +1 -0
- package/example-course-project/lesson1/task2/task.md +47 -0
- package/example-course-project/lesson1/task2/tests/Tests.txt +0 -0
- package/package.json +19 -0
- package/src/@types/mime-types.d.ts +3 -0
- package/src/courseFormat/AnswerPlaceholder.ts +121 -0
- package/src/courseFormat/AnswerPlaceholderComparator.ts +7 -0
- package/src/courseFormat/AnswerPlaceholderDependency.ts +122 -0
- package/src/courseFormat/CheckFeedback.ts +71 -0
- package/src/courseFormat/CheckResult.ts +92 -0
- package/src/courseFormat/CheckResultSeverity.ts +13 -0
- package/src/courseFormat/CheckStatus.ts +5 -0
- package/src/courseFormat/Course.ts +201 -0
- package/src/courseFormat/CourseMode.ts +4 -0
- package/src/courseFormat/CourseVisibility.ts +4 -0
- package/src/courseFormat/CourseraCourse.ts +10 -0
- package/src/courseFormat/DescriptionFormat.ts +5 -0
- package/src/courseFormat/EduCourse.ts +41 -0
- package/src/courseFormat/EduFile.ts +133 -0
- package/src/courseFormat/EduFileErrorHighlightLevel.ts +5 -0
- package/src/courseFormat/EduFormatNames.ts +95 -0
- package/src/courseFormat/EduTestInfo.ts +87 -0
- package/src/courseFormat/EduVersions.ts +2 -0
- package/src/courseFormat/FileContents.ts +97 -0
- package/src/courseFormat/FileContentsFactory.ts +19 -0
- package/src/courseFormat/FrameworkLesson.ts +29 -0
- package/src/courseFormat/ItemContainer.ts +47 -0
- package/src/courseFormat/JBAccountUserInfo.ts +21 -0
- package/src/courseFormat/Language.ts +31 -0
- package/src/courseFormat/Lesson.ts +69 -0
- package/src/courseFormat/LessonContainer.ts +65 -0
- package/src/courseFormat/PluginInfo.ts +15 -0
- package/src/courseFormat/Section.ts +29 -0
- package/src/courseFormat/StudyItem.ts +55 -0
- package/src/courseFormat/Tags.ts +45 -0
- package/src/courseFormat/TaskFile.ts +88 -0
- package/src/courseFormat/UserInfo.ts +3 -0
- package/src/courseFormat/Vendor.ts +15 -0
- package/src/courseFormat/attempts/Attempt.ts +28 -0
- package/src/courseFormat/attempts/AttemptBase.ts +24 -0
- package/src/courseFormat/attempts/DataTaskAttempt.ts +19 -0
- package/src/courseFormat/attempts/Dataset.ts +13 -0
- package/src/courseFormat/fileUtils.ts +31 -0
- package/src/courseFormat/hyperskill/HyperskillCourse.ts +24 -0
- package/src/courseFormat/hyperskill/HyperskillProject.ts +10 -0
- package/src/courseFormat/hyperskill/HyperskillStage.ts +15 -0
- package/src/courseFormat/hyperskill/HyperskillTaskType.ts +23 -0
- package/src/courseFormat/hyperskill/HyperskillTopic.ts +5 -0
- package/src/courseFormat/loggerUtils.ts +3 -0
- package/src/courseFormat/stepik/StepikCourse.ts +10 -0
- package/src/courseFormat/stepik/StepikLesson.ts +11 -0
- package/src/courseFormat/tasks/AnswerTask.ts +13 -0
- package/src/courseFormat/tasks/CodeTask.ts +42 -0
- package/src/courseFormat/tasks/DataTask.ts +37 -0
- package/src/courseFormat/tasks/EduTask.ts +26 -0
- package/src/courseFormat/tasks/IdeTask.ts +17 -0
- package/src/courseFormat/tasks/NumberTask.ts +17 -0
- package/src/courseFormat/tasks/OutputTask.ts +21 -0
- package/src/courseFormat/tasks/OutputTaskBase.ts +23 -0
- package/src/courseFormat/tasks/RemoteEduTask.ts +18 -0
- package/src/courseFormat/tasks/StringTask.ts +17 -0
- package/src/courseFormat/tasks/TableTask.ts +51 -0
- package/src/courseFormat/tasks/Task.ts +181 -0
- package/src/courseFormat/tasks/TheoryTask.ts +19 -0
- package/src/courseFormat/tasks/UnsupportedTask.ts +17 -0
- package/src/courseFormat/tasks/choice/ChoiceOption.ts +37 -0
- package/src/courseFormat/tasks/choice/ChoiceOptionStatus.ts +5 -0
- package/src/courseFormat/tasks/choice/ChoiceTask.ts +57 -0
- package/src/courseFormat/tasks/matching/MatchingTask.ts +19 -0
- package/src/courseFormat/tasks/matching/SortingBasedTask.ts +59 -0
- package/src/courseFormat/tasks/matching/SortingTask.ts +17 -0
- package/src/courseFormat/uiMessages.ts +12 -0
- package/src/disk-loader.ts +463 -0
- package/src/index.ts +33 -0
- package/src/models.ts +54 -0
- package/src/zip-loader.ts +583 -0
- package/test/load-course.test.js +279 -0
- package/test/load-zip-course.test.js +73 -0
- package/tsconfig.json +15 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { CheckStatus } from "../CheckStatus"
|
|
2
|
+
import { Task } from "./Task"
|
|
3
|
+
|
|
4
|
+
export class IdeTask extends Task {
|
|
5
|
+
constructor()
|
|
6
|
+
constructor(name: string)
|
|
7
|
+
constructor(name: string, id: number, position: number, updateDate: Date, status: CheckStatus)
|
|
8
|
+
constructor(name?: string, id?: number, position?: number, updateDate?: Date, status?: CheckStatus) {
|
|
9
|
+
super(name as string, id as number, position as number, updateDate as Date, status as CheckStatus)
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
get itemType(): string {
|
|
13
|
+
return IdeTask.IDE_TASK_TYPE
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
static IDE_TASK_TYPE = "ide"
|
|
17
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { CheckStatus } from "../CheckStatus"
|
|
2
|
+
import { AnswerTask } from "./AnswerTask"
|
|
3
|
+
|
|
4
|
+
export class NumberTask extends AnswerTask {
|
|
5
|
+
constructor()
|
|
6
|
+
constructor(name: string)
|
|
7
|
+
constructor(name: string, id: number, position: number, updateDate: Date, status: CheckStatus)
|
|
8
|
+
constructor(name?: string, id?: number, position?: number, updateDate?: Date, status?: CheckStatus) {
|
|
9
|
+
super(name as string, id as number, position as number, updateDate as Date, status as CheckStatus)
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
get itemType(): string {
|
|
13
|
+
return NumberTask.NUMBER_TASK_TYPE
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
static NUMBER_TASK_TYPE = "number"
|
|
17
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { CheckStatus } from "../CheckStatus"
|
|
2
|
+
import { OutputTaskBase } from "./OutputTaskBase"
|
|
3
|
+
|
|
4
|
+
export class OutputTask extends OutputTaskBase {
|
|
5
|
+
constructor()
|
|
6
|
+
constructor(name: string)
|
|
7
|
+
constructor(name: string, id: number, position: number, updateDate: Date, status: CheckStatus)
|
|
8
|
+
constructor(name?: string, id?: number, position?: number, updateDate?: Date, status?: CheckStatus) {
|
|
9
|
+
super(name as string, id as number, position as number, updateDate as Date, status as CheckStatus)
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
get itemType(): string {
|
|
13
|
+
return OutputTask.OUTPUT_TASK_TYPE
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
get isToSubmitToRemote(): boolean {
|
|
17
|
+
return this.checkStatus !== CheckStatus.Unchecked
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
static OUTPUT_TASK_TYPE = "output"
|
|
21
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { CheckStatus } from "../CheckStatus"
|
|
2
|
+
import { Task } from "./Task"
|
|
3
|
+
|
|
4
|
+
export abstract class OutputTaskBase extends Task {
|
|
5
|
+
inputFileName = OutputTaskBase.INPUT_PATTERN_NAME
|
|
6
|
+
outputFileName = OutputTaskBase.OUTPUT_PATTERN_NAME
|
|
7
|
+
latestOutputFileName = OutputTaskBase.LATEST_OUTPUT_PATTERN_NAME
|
|
8
|
+
|
|
9
|
+
constructor()
|
|
10
|
+
constructor(name: string)
|
|
11
|
+
constructor(name: string, id: number, position: number, updateDate: Date, status: CheckStatus)
|
|
12
|
+
constructor(name?: string, id?: number, position?: number, updateDate?: Date, status?: CheckStatus) {
|
|
13
|
+
super(name as string, id as number, position as number, updateDate as Date, status as CheckStatus)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
get supportSubmissions(): boolean {
|
|
17
|
+
return true
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
static OUTPUT_PATTERN_NAME = "output.txt"
|
|
21
|
+
static INPUT_PATTERN_NAME = "input.txt"
|
|
22
|
+
static LATEST_OUTPUT_PATTERN_NAME = "latest_output.txt"
|
|
23
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { CheckStatus } from "../CheckStatus"
|
|
2
|
+
import { EduTask } from "./EduTask"
|
|
3
|
+
|
|
4
|
+
export class RemoteEduTask extends EduTask {
|
|
5
|
+
checkProfile = ""
|
|
6
|
+
|
|
7
|
+
constructor()
|
|
8
|
+
constructor(name: string, id: number, position: number, updateDate: Date, status: CheckStatus)
|
|
9
|
+
constructor(name?: string, id?: number, position?: number, updateDate?: Date, status?: CheckStatus) {
|
|
10
|
+
super(name as string, id as number, position as number, updateDate as Date, status as CheckStatus)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
get itemType(): string {
|
|
14
|
+
return RemoteEduTask.REMOTE_EDU_TASK_TYPE
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
static REMOTE_EDU_TASK_TYPE = "remote_edu"
|
|
18
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { CheckStatus } from "../CheckStatus"
|
|
2
|
+
import { AnswerTask } from "./AnswerTask"
|
|
3
|
+
|
|
4
|
+
export class StringTask extends AnswerTask {
|
|
5
|
+
constructor()
|
|
6
|
+
constructor(name: string)
|
|
7
|
+
constructor(name: string, id: number, position: number, updateDate: Date, status: CheckStatus)
|
|
8
|
+
constructor(name?: string, id?: number, position?: number, updateDate?: Date, status?: CheckStatus) {
|
|
9
|
+
super(name as string, id as number, position as number, updateDate as Date, status as CheckStatus)
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
get itemType(): string {
|
|
13
|
+
return StringTask.STRING_TASK_TYPE
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
static STRING_TASK_TYPE = "string"
|
|
17
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { CheckStatus } from "../CheckStatus"
|
|
2
|
+
import { Task } from "./Task"
|
|
3
|
+
import { logger } from "../loggerUtils"
|
|
4
|
+
|
|
5
|
+
export class TableTask extends Task {
|
|
6
|
+
isMultipleChoice = false
|
|
7
|
+
rows: string[] = []
|
|
8
|
+
columns: string[] = []
|
|
9
|
+
selected: boolean[][] = []
|
|
10
|
+
|
|
11
|
+
constructor()
|
|
12
|
+
constructor(name: string)
|
|
13
|
+
constructor(name: string, id: number, position: number, updateDate: Date, status: CheckStatus)
|
|
14
|
+
constructor(name?: string, id?: number, position?: number, updateDate?: Date, status?: CheckStatus) {
|
|
15
|
+
super(name as string, id as number, position as number, updateDate as Date, status as CheckStatus)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
get itemType(): string {
|
|
19
|
+
return TableTask.TABLE_TASK_TYPE
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
choose(rowIndex: number, columnIndex: number): void {
|
|
23
|
+
if (rowIndex < 0 || rowIndex >= this.rows.length || columnIndex < 0 || columnIndex >= this.columns.length) {
|
|
24
|
+
logger("TableTask").error("There was an attempt to choose a cell with invalid indices")
|
|
25
|
+
return
|
|
26
|
+
}
|
|
27
|
+
if (!this.isMultipleChoice) {
|
|
28
|
+
this.clearSelectedInRow(rowIndex)
|
|
29
|
+
}
|
|
30
|
+
this.selected[rowIndex][columnIndex] = !this.selected[rowIndex][columnIndex]
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
clearSelectedVariants(): void {
|
|
34
|
+
for (let rowIndex = 0; rowIndex < this.selected.length; rowIndex += 1) {
|
|
35
|
+
this.clearSelectedInRow(rowIndex)
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
private clearSelectedInRow(rowIndex: number): void {
|
|
40
|
+
this.selected[rowIndex] = this.selected[rowIndex].map(() => false)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
createTable(rows: string[], columns: string[], isCheckbox = false): void {
|
|
44
|
+
this.rows = rows
|
|
45
|
+
this.columns = columns
|
|
46
|
+
this.isMultipleChoice = isCheckbox
|
|
47
|
+
this.selected = rows.map(() => columns.map(() => false))
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
static TABLE_TASK_TYPE = "table"
|
|
51
|
+
}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { CheckFeedback } from "../CheckFeedback"
|
|
2
|
+
import { CheckStatus } from "../CheckStatus"
|
|
3
|
+
import { DescriptionFormat } from "../DescriptionFormat"
|
|
4
|
+
import { ItemContainer } from "../ItemContainer"
|
|
5
|
+
import type { Lesson } from "../Lesson"
|
|
6
|
+
import { Course } from "../Course"
|
|
7
|
+
import { TaskFile } from "../TaskFile"
|
|
8
|
+
import { StudyItem } from "../StudyItem"
|
|
9
|
+
import { logger } from "../loggerUtils"
|
|
10
|
+
|
|
11
|
+
function getLessonModuleLazy(): { Lesson: typeof Lesson } {
|
|
12
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
13
|
+
return require("../Lesson")
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export abstract class Task extends StudyItem {
|
|
17
|
+
private _taskFiles: Map<string, TaskFile> = new Map()
|
|
18
|
+
|
|
19
|
+
get taskFiles(): Map<string, TaskFile> {
|
|
20
|
+
return this._taskFiles
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
set taskFiles(value: Map<string, TaskFile>) {
|
|
24
|
+
this._taskFiles = value
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
feedback?: CheckFeedback
|
|
28
|
+
descriptionText = ""
|
|
29
|
+
descriptionFormat: DescriptionFormat = DescriptionFormat.MD
|
|
30
|
+
feedbackLink?: string
|
|
31
|
+
solutionHidden?: boolean
|
|
32
|
+
record = -1
|
|
33
|
+
isUpToDate = true
|
|
34
|
+
|
|
35
|
+
protected checkStatus: CheckStatus = CheckStatus.Unchecked
|
|
36
|
+
|
|
37
|
+
get status(): CheckStatus {
|
|
38
|
+
return this.checkStatus
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
set status(status: CheckStatus) {
|
|
42
|
+
for (const taskFile of this._taskFiles.values()) {
|
|
43
|
+
for (const placeholder of taskFile.answerPlaceholders) {
|
|
44
|
+
placeholder.status = status
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
if (this.checkStatus !== status) {
|
|
48
|
+
this.feedback = undefined
|
|
49
|
+
}
|
|
50
|
+
this.checkStatus = status
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
get lesson(): Lesson {
|
|
54
|
+
const LessonClass = getLessonModuleLazy().Lesson
|
|
55
|
+
if (!(this.parent instanceof LessonClass)) {
|
|
56
|
+
throw new Error(`Lesson is null for task ${this.name}`)
|
|
57
|
+
}
|
|
58
|
+
return this.parent as Lesson
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
get isPluginTaskType(): boolean {
|
|
62
|
+
return true
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
get supportSubmissions(): boolean {
|
|
66
|
+
return false
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
get isToSubmitToRemote(): boolean {
|
|
70
|
+
return false
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
get isChangedOnFailed(): boolean {
|
|
74
|
+
return false
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
get course(): Course {
|
|
78
|
+
return this.lesson.course
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
get files(): TaskFile[] {
|
|
82
|
+
return this.getTaskFileValues()
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
constructor()
|
|
86
|
+
constructor(name: string)
|
|
87
|
+
constructor(name: string, id: number, position: number, updateDate: Date, status: CheckStatus)
|
|
88
|
+
constructor(name?: string, id?: number, position?: number, updateDate?: Date, status?: CheckStatus) {
|
|
89
|
+
super(name)
|
|
90
|
+
if (id !== undefined) this.id = id
|
|
91
|
+
if (position !== undefined) this.index = position
|
|
92
|
+
if (updateDate !== undefined) this.updateDate = updateDate
|
|
93
|
+
if (status !== undefined) this.checkStatus = status
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
override init(parentItem: ItemContainer, isRestarted: boolean): void {
|
|
97
|
+
this.parent = parentItem
|
|
98
|
+
for (const taskFile of this._taskFiles.values()) {
|
|
99
|
+
taskFile.initTaskFile(this, isRestarted)
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
getTaskFile(name: string): TaskFile | undefined {
|
|
104
|
+
return this._taskFiles.get(name)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
addTaskFile(name: string, isVisible = true): TaskFile {
|
|
108
|
+
const taskFile = new TaskFile()
|
|
109
|
+
taskFile.task = this
|
|
110
|
+
taskFile.name = name
|
|
111
|
+
taskFile.isVisible = isVisible
|
|
112
|
+
this._taskFiles.set(name, taskFile)
|
|
113
|
+
return taskFile
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
addTaskFileInstance(taskFile: TaskFile): void {
|
|
117
|
+
taskFile.task = this
|
|
118
|
+
this._taskFiles.set(taskFile.name, taskFile)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
addTaskFileAt(taskFile: TaskFile, position: number): void {
|
|
122
|
+
taskFile.task = this
|
|
123
|
+
if (position < 0 || position > this._taskFiles.size) {
|
|
124
|
+
throw new Error("IndexOutOfBounds")
|
|
125
|
+
}
|
|
126
|
+
const entries = Array.from(this._taskFiles.entries())
|
|
127
|
+
entries.splice(position, 0, [taskFile.name, taskFile])
|
|
128
|
+
this._taskFiles = new Map(entries)
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
setTaskFileValues(taskFiles: TaskFile[]): void {
|
|
132
|
+
this._taskFiles.clear()
|
|
133
|
+
for (const taskFile of taskFiles) {
|
|
134
|
+
this._taskFiles.set(taskFile.name, taskFile)
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
getTaskFileValues(): TaskFile[] {
|
|
139
|
+
return Array.from(this._taskFiles.values())
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
removeTaskFile(taskFile: string): TaskFile | undefined {
|
|
143
|
+
const value = this._taskFiles.get(taskFile)
|
|
144
|
+
this._taskFiles.delete(taskFile)
|
|
145
|
+
return value
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
taskFileIndex(taskFile: string): number | undefined {
|
|
149
|
+
const index = Array.from(this._taskFiles.keys()).indexOf(taskFile)
|
|
150
|
+
return index === -1 ? undefined : index
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
equals(other: Task): boolean {
|
|
154
|
+
if (this === other) return true
|
|
155
|
+
if (this.index !== other.index) return false
|
|
156
|
+
if (this.name !== other.name) return false
|
|
157
|
+
if (this._taskFiles !== other._taskFiles) return false
|
|
158
|
+
if (this.descriptionText !== other.descriptionText) return false
|
|
159
|
+
return this.descriptionFormat === other.descriptionFormat
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
hashCode(): number {
|
|
163
|
+
let result = hashString(this.name)
|
|
164
|
+
result = 31 * result + this.index
|
|
165
|
+
result = 31 * result + this._taskFiles.size
|
|
166
|
+
result = 31 * result + hashString(this.descriptionText)
|
|
167
|
+
result = 31 * result + hashString(this.descriptionFormat)
|
|
168
|
+
return result
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
static LOG = logger("Task")
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function hashString(value: string): number {
|
|
175
|
+
let hash = 0
|
|
176
|
+
for (let i = 0; i < value.length; i += 1) {
|
|
177
|
+
hash = (hash << 5) - hash + value.charCodeAt(i)
|
|
178
|
+
hash |= 0
|
|
179
|
+
}
|
|
180
|
+
return hash
|
|
181
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { CheckStatus } from "../CheckStatus"
|
|
2
|
+
import { Task } from "./Task"
|
|
3
|
+
|
|
4
|
+
export class TheoryTask extends Task {
|
|
5
|
+
postSubmissionOnOpen = true
|
|
6
|
+
|
|
7
|
+
constructor()
|
|
8
|
+
constructor(name: string)
|
|
9
|
+
constructor(name: string, id: number, position: number, updateDate: Date, status: CheckStatus)
|
|
10
|
+
constructor(name?: string, id?: number, position?: number, updateDate?: Date, status?: CheckStatus) {
|
|
11
|
+
super(name as string, id as number, position as number, updateDate as Date, status as CheckStatus)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
get itemType(): string {
|
|
15
|
+
return TheoryTask.THEORY_TASK_TYPE
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
static THEORY_TASK_TYPE = "theory"
|
|
19
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { CheckStatus } from "../CheckStatus"
|
|
2
|
+
import { Task } from "./Task"
|
|
3
|
+
|
|
4
|
+
export class UnsupportedTask extends Task {
|
|
5
|
+
constructor()
|
|
6
|
+
constructor(name: string)
|
|
7
|
+
constructor(name: string, id: number, position: number, updateDate: Date, status: CheckStatus)
|
|
8
|
+
constructor(name?: string, id?: number, position?: number, updateDate?: Date, status?: CheckStatus) {
|
|
9
|
+
super(name as string, id as number, position as number, updateDate as Date, status as CheckStatus)
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
get itemType(): string {
|
|
13
|
+
return UnsupportedTask.UNSUPPORTED_TASK_TYPE
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
static UNSUPPORTED_TASK_TYPE = "unsupported"
|
|
17
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { ChoiceOptionStatus } from "./ChoiceOptionStatus"
|
|
2
|
+
|
|
3
|
+
export class ChoiceOption {
|
|
4
|
+
text = ""
|
|
5
|
+
status: ChoiceOptionStatus = ChoiceOptionStatus.UNKNOWN
|
|
6
|
+
|
|
7
|
+
constructor()
|
|
8
|
+
constructor(text: string)
|
|
9
|
+
constructor(text: string, status: ChoiceOptionStatus)
|
|
10
|
+
constructor(text?: string, status?: ChoiceOptionStatus) {
|
|
11
|
+
if (text !== undefined) {
|
|
12
|
+
this.text = text
|
|
13
|
+
}
|
|
14
|
+
if (status !== undefined) {
|
|
15
|
+
this.status = status
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
equals(other: ChoiceOption): boolean {
|
|
20
|
+
return this.text === other.text && this.status === other.status
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
hashCode(): number {
|
|
24
|
+
let result = hashString(this.text)
|
|
25
|
+
result = 31 * result + hashString(this.status)
|
|
26
|
+
return result
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function hashString(value: string): number {
|
|
31
|
+
let hash = 0
|
|
32
|
+
for (let i = 0; i < value.length; i += 1) {
|
|
33
|
+
hash = (hash << 5) - hash + value.charCodeAt(i)
|
|
34
|
+
hash |= 0
|
|
35
|
+
}
|
|
36
|
+
return hash
|
|
37
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { CheckStatus } from "../../CheckStatus"
|
|
2
|
+
import { message } from "../../uiMessages"
|
|
3
|
+
import { Task } from "../Task"
|
|
4
|
+
import { ChoiceOption } from "./ChoiceOption"
|
|
5
|
+
|
|
6
|
+
export class ChoiceTask extends Task {
|
|
7
|
+
choiceOptions: ChoiceOption[] = []
|
|
8
|
+
isMultipleChoice = false
|
|
9
|
+
selectedVariants: number[] = []
|
|
10
|
+
messageCorrect: string = message("check.correct.solution")
|
|
11
|
+
messageIncorrect: string = message("check.incorrect.solution")
|
|
12
|
+
quizHeader?: string
|
|
13
|
+
canCheckLocally = true
|
|
14
|
+
|
|
15
|
+
constructor()
|
|
16
|
+
constructor(name: string, id: number, position: number, updateDate: Date, status: CheckStatus)
|
|
17
|
+
constructor(name?: string, id?: number, position?: number, updateDate?: Date, status?: CheckStatus) {
|
|
18
|
+
super(name as string, id as number, position as number, updateDate as Date, status as CheckStatus)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
get itemType(): string {
|
|
22
|
+
return ChoiceTask.CHOICE_TASK_TYPE
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
get isPluginTaskType(): boolean {
|
|
26
|
+
return false
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
get isChangedOnFailed(): boolean {
|
|
30
|
+
return !this.canCheckLocally
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
get isToSubmitToRemote(): boolean {
|
|
34
|
+
return this.status !== CheckStatus.Unchecked
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
get presentableQuizHeader(): string {
|
|
38
|
+
if (this.quizHeader) return this.quizHeader
|
|
39
|
+
return this.isMultipleChoice
|
|
40
|
+
? message("course.creator.create.choice.task.multiple.label")
|
|
41
|
+
: message("course.creator.create.choice.task.single.label")
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
addSelectedVariant(variant: number): void {
|
|
45
|
+
this.selectedVariants.push(variant)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
removeSelectedVariant(variant: number): void {
|
|
49
|
+
this.selectedVariants = this.selectedVariants.filter((value) => value !== variant)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
clearSelectedVariants(): void {
|
|
53
|
+
this.selectedVariants = []
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
static CHOICE_TASK_TYPE = "choice"
|
|
57
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { CheckStatus } from "../../CheckStatus"
|
|
2
|
+
import { SortingBasedTask } from "./SortingBasedTask"
|
|
3
|
+
|
|
4
|
+
export class MatchingTask extends SortingBasedTask {
|
|
5
|
+
captions: string[] = []
|
|
6
|
+
|
|
7
|
+
constructor()
|
|
8
|
+
constructor(name: string)
|
|
9
|
+
constructor(name: string, id: number, position: number, updateDate: Date, status: CheckStatus)
|
|
10
|
+
constructor(name?: string, id?: number, position?: number, updateDate?: Date, status?: CheckStatus) {
|
|
11
|
+
super(name as string, id as number, position as number, updateDate as Date, status as CheckStatus)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
get itemType(): string {
|
|
15
|
+
return MatchingTask.MATCHING_TASK_TYPE
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
static MATCHING_TASK_TYPE = "matching"
|
|
19
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { CheckStatus } from "../../CheckStatus"
|
|
2
|
+
import { logger } from "../../loggerUtils"
|
|
3
|
+
import { Task } from "../Task"
|
|
4
|
+
|
|
5
|
+
export abstract class SortingBasedTask extends Task {
|
|
6
|
+
private _options: string[] = []
|
|
7
|
+
ordering: number[] = []
|
|
8
|
+
|
|
9
|
+
get options(): string[] {
|
|
10
|
+
return this._options
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
set options(value: string[]) {
|
|
14
|
+
this.ordering = value.map((_, index) => index)
|
|
15
|
+
this._options = value
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
constructor()
|
|
19
|
+
constructor(name: string)
|
|
20
|
+
constructor(name: string, id: number, position: number, updateDate: Date, status: CheckStatus)
|
|
21
|
+
constructor(name?: string, id?: number, position?: number, updateDate?: Date, status?: CheckStatus) {
|
|
22
|
+
super(name as string, id as number, position as number, updateDate as Date, status as CheckStatus)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
getOrderedOptions(): string[] {
|
|
26
|
+
return this.options.map((_, index) => this.options[this.ordering[index]])
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
moveOptionUp(index: number): void {
|
|
30
|
+
const targetIndex = index - 1
|
|
31
|
+
if (targetIndex < 0) {
|
|
32
|
+
const message = "There was an attempt to move the option up out of bounds"
|
|
33
|
+
logger("SortingBasedTask").error(message)
|
|
34
|
+
throw new Error(message)
|
|
35
|
+
}
|
|
36
|
+
this.swapOptions(index, targetIndex)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
moveOptionDown(index: number): void {
|
|
40
|
+
const targetIndex = index + 1
|
|
41
|
+
if (targetIndex === this.options.length) {
|
|
42
|
+
const message = "There was an attempt to move the option down out of bounds"
|
|
43
|
+
logger("SortingBasedTask").error(message)
|
|
44
|
+
throw new Error(message)
|
|
45
|
+
}
|
|
46
|
+
this.swapOptions(index, targetIndex)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
swapOptions(firstColumnIndex: number, secondColumnIndex: number): void {
|
|
50
|
+
const firstOptionIndex = this.ordering[firstColumnIndex]
|
|
51
|
+
const secondOptionIndex = this.ordering[secondColumnIndex]
|
|
52
|
+
this.ordering[firstColumnIndex] = secondOptionIndex
|
|
53
|
+
this.ordering[secondColumnIndex] = firstOptionIndex
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
restoreInitialOrdering(): void {
|
|
57
|
+
this.ordering = this.options.map((_, index) => index)
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { CheckStatus } from "../../CheckStatus"
|
|
2
|
+
import { SortingBasedTask } from "./SortingBasedTask"
|
|
3
|
+
|
|
4
|
+
export class SortingTask extends SortingBasedTask {
|
|
5
|
+
constructor()
|
|
6
|
+
constructor(name: string)
|
|
7
|
+
constructor(name: string, id: number, position: number, updateDate: Date, status: CheckStatus)
|
|
8
|
+
constructor(name?: string, id?: number, position?: number, updateDate?: Date, status?: CheckStatus) {
|
|
9
|
+
super(name as string, id as number, position as number, updateDate as Date, status as CheckStatus)
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
get itemType(): string {
|
|
13
|
+
return SortingTask.SORTING_TASK_TYPE
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
static SORTING_TASK_TYPE = "sorting"
|
|
17
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
const FORMAT_BUNDLE = "messages.EduFormatBundle"
|
|
2
|
+
|
|
3
|
+
export function message(key: string, ...params: Array<string | number>): string {
|
|
4
|
+
if (params.length === 0) {
|
|
5
|
+
return key
|
|
6
|
+
}
|
|
7
|
+
return params.reduce((result: string, param, index) => {
|
|
8
|
+
return result.replace(new RegExp(`\\{${index}\\}`, "g"), String(param))
|
|
9
|
+
}, key)
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export { FORMAT_BUNDLE }
|