@tinyweb_dev/oe-exam-sdk 0.2.1 → 0.2.2
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/dist/components/exams/take/components/QuestionRenderer.js +10 -2
- package/dist/components/exams/take/components/question-renderers/FindWordsInMatrixRenderer.d.ts +4 -0
- package/dist/components/exams/take/components/question-renderers/FindWordsInMatrixRenderer.js +389 -0
- package/dist/components/exams/take/components/question-renderers/index.d.ts +1 -0
- package/dist/components/exams/take/components/question-renderers/index.js +1 -0
- package/dist/components/exams/take/types.d.ts +50 -0
- package/dist/components/exams/take/utils/question-transformers.d.ts +41 -1
- package/dist/components/exams/take/utils/question-transformers.js +24 -0
- package/dist/components/questions/_shared/config/question-types.config.js +6 -0
- package/dist/components/questions/_shared/types/find-words-in-matrix.type.d.ts +18 -0
- package/dist/components/questions/_shared/types/find-words-in-matrix.type.js +1 -0
- package/dist/components/questions/creator/question-type-registry.js +2 -0
- package/dist/components/questions/question-bank/QuestionEditorRenderer.d.ts +2 -1
- package/dist/components/questions/question-bank/QuestionEditorRenderer.js +16 -0
- package/dist/components/questions/types/crossword-puzzle/CrosswordPuzzleClient.js +3 -3
- package/dist/components/questions/types/find-words-in-matrix/FindWordsInMatrixClient.d.ts +9 -0
- package/dist/components/questions/types/find-words-in-matrix/FindWordsInMatrixClient.js +69 -0
- package/dist/components/questions/types/find-words-in-matrix/FindWordsInMatrixCreator.d.ts +8 -0
- package/dist/components/questions/types/find-words-in-matrix/FindWordsInMatrixCreator.js +302 -0
- package/dist/components/questions/types/find-words-in-matrix/index.d.ts +4 -0
- package/dist/components/questions/types/find-words-in-matrix/index.js +4 -0
- package/dist/components/questions/types/find-words-in-matrix/register.d.ts +2 -0
- package/dist/components/questions/types/find-words-in-matrix/register.js +29 -0
- package/dist/components/questions/types/find-words-in-matrix/transform.d.ts +2 -0
- package/dist/components/questions/types/find-words-in-matrix/transform.js +89 -0
- package/dist/shared/constants/question-skills.js +2 -0
- package/dist/shared/lib/utils/question-reverse-transform.js +63 -0
- package/dist/shared/lib/utils/question-transform.js +2 -0
- package/dist/shared/types/common.types.d.ts +1 -1
- package/dist/shared/types/questions/find-words-in-matrix.d.ts +71 -0
- package/dist/shared/types/questions/find-words-in-matrix.js +8 -0
- package/dist/shared/types/questions/index.d.ts +1 -0
- package/dist/shared/types/questions/index.js +2 -0
- package/package.json +1 -1
|
@@ -79,6 +79,7 @@ export const QUESTION_TYPE_SKILLS = {
|
|
|
79
79
|
'FILL_BLANK': SkillEnum.READING,
|
|
80
80
|
'WORD_FILL_STRUCTURED_FORM': SkillEnum.READING,
|
|
81
81
|
'CROSSWORD_PUZZLE': SkillEnum.READING,
|
|
82
|
+
'FIND_WORDS_IN_MATRIX': SkillEnum.READING,
|
|
82
83
|
// ========================================
|
|
83
84
|
// WRITING SKILLS (Viết)
|
|
84
85
|
// ========================================
|
|
@@ -206,6 +207,7 @@ export const QUESTION_TYPE_LABELS = {
|
|
|
206
207
|
'MATCH_BY_WRITING_ANSWER': 'Ghép đáp án bằng cách viết',
|
|
207
208
|
'WORD_FILL_STRUCTURED_FORM': 'Điền từ vào biểu mẫu có cấu trúc',
|
|
208
209
|
'CROSSWORD_PUZZLE': 'Giải ô chữ (Crossword)',
|
|
210
|
+
'FIND_WORDS_IN_MATRIX': 'Tìm từ trong ma trận (Word Search)',
|
|
209
211
|
// ========================================
|
|
210
212
|
// WRITING SKILLS (Viết)
|
|
211
213
|
// ========================================
|
|
@@ -447,6 +447,7 @@ const handlers = {
|
|
|
447
447
|
SPEAKING_CUE_CARD: reverseSimpleAnswer,
|
|
448
448
|
GN_SPEAKING_INTERVIEW: reverseGroupPayload,
|
|
449
449
|
CROSSWORD_PUZZLE: reverseCrosswordPuzzle,
|
|
450
|
+
FIND_WORDS_IN_MATRIX: reverseFindWordsInMatrix,
|
|
450
451
|
};
|
|
451
452
|
function reverseCrosswordPuzzle(apiQuestion) {
|
|
452
453
|
const apiContent = (apiQuestion.content || {});
|
|
@@ -501,6 +502,68 @@ function reverseCrosswordPuzzle(apiQuestion) {
|
|
|
501
502
|
},
|
|
502
503
|
};
|
|
503
504
|
}
|
|
505
|
+
function reverseFindWordsInMatrix(apiQuestion) {
|
|
506
|
+
const apiContent = (apiQuestion.content || {});
|
|
507
|
+
const apiAnswer = (apiQuestion.correctAnswer || apiQuestion.correct_answer || apiQuestion.answer || {});
|
|
508
|
+
const type = apiContent.type || (Array.isArray(apiContent.categories) && apiContent.categories.length > 0 ? 'CATEGORIZE' : 'WORD_BANK');
|
|
509
|
+
const rows = apiContent.gridSize?.rows || (Array.isArray(apiContent.grid) ? apiContent.grid.length : 14);
|
|
510
|
+
const cols = apiContent.gridSize?.cols || (Array.isArray(apiContent.grid?.[0]) ? apiContent.grid[0].length : 14);
|
|
511
|
+
const title = apiContent.title || '';
|
|
512
|
+
const grid = Array.isArray(apiContent.grid) ? apiContent.grid : [];
|
|
513
|
+
const categories = Array.isArray(apiContent.categories) ? apiContent.categories : [];
|
|
514
|
+
const wordBank = Array.isArray(apiContent.wordBank) ? apiContent.wordBank : [];
|
|
515
|
+
const correctWords = Array.isArray(apiAnswer.words) ? apiAnswer.words : [];
|
|
516
|
+
const correctMap = new Map();
|
|
517
|
+
for (const cw of correctWords) {
|
|
518
|
+
if (cw.wordId) {
|
|
519
|
+
correctMap.set(cw.wordId, cw);
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
const words = wordBank.map((wb) => {
|
|
523
|
+
const isEx = Boolean(wb.isExample);
|
|
524
|
+
const correctInfo = correctMap.get(wb.id);
|
|
525
|
+
let path = correctInfo?.path;
|
|
526
|
+
let categoryId = wb.categoryId || correctInfo?.categoryId;
|
|
527
|
+
if (isEx && apiContent.exampleSelection?.wordId === wb.id) {
|
|
528
|
+
path = apiContent.exampleSelection.path;
|
|
529
|
+
if (apiContent.exampleSelection.categoryId) {
|
|
530
|
+
categoryId = apiContent.exampleSelection.categoryId;
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
return {
|
|
534
|
+
id: wb.id || `w_${Math.random().toString(36).substring(2, 9)}`,
|
|
535
|
+
word: wb.word || '',
|
|
536
|
+
isExample: isEx,
|
|
537
|
+
...(categoryId ? { categoryId } : {}),
|
|
538
|
+
path: path || [],
|
|
539
|
+
};
|
|
540
|
+
});
|
|
541
|
+
return {
|
|
542
|
+
content: {
|
|
543
|
+
type,
|
|
544
|
+
title,
|
|
545
|
+
rows,
|
|
546
|
+
cols,
|
|
547
|
+
gridSize: { rows, cols },
|
|
548
|
+
grid,
|
|
549
|
+
categories,
|
|
550
|
+
wordBank,
|
|
551
|
+
words,
|
|
552
|
+
...(apiContent.exampleSelection ? { exampleSelection: apiContent.exampleSelection } : {}),
|
|
553
|
+
},
|
|
554
|
+
answer: {
|
|
555
|
+
type,
|
|
556
|
+
title,
|
|
557
|
+
rows,
|
|
558
|
+
cols,
|
|
559
|
+
grid,
|
|
560
|
+
categories,
|
|
561
|
+
words,
|
|
562
|
+
caseSensitive: Boolean(apiAnswer.caseSensitive),
|
|
563
|
+
explanation: apiQuestion.explanation || '',
|
|
564
|
+
},
|
|
565
|
+
};
|
|
566
|
+
}
|
|
504
567
|
export function transformApiQuestionToFrontend(apiQuestion) {
|
|
505
568
|
const questionType = String(apiQuestion.questionType ?? apiQuestion.question_type ?? apiQuestion.type ?? '');
|
|
506
569
|
const handlerResult = (handlers[questionType] ?? defaultReverse)(apiQuestion);
|
|
@@ -42,6 +42,7 @@ import { transformSpeakingCueCard } from '../../../components/questions/types/sp
|
|
|
42
42
|
import { transformGNSpeakingInterview } from '../../../components/questions/types/gn-speaking-interview/transform';
|
|
43
43
|
import { transformWordFillStructuredForm } from '../../../components/questions/types/word-fill-structured-form/transform';
|
|
44
44
|
import { transformCrosswordPuzzle } from '../../../components/questions/types/crossword-puzzle/transform';
|
|
45
|
+
import { transformFindWordsInMatrix } from '../../../components/questions/types/find-words-in-matrix/transform';
|
|
45
46
|
// ─── Handler map ────────────────────────────────────────────────────────────
|
|
46
47
|
const questionTransformHandlers = {
|
|
47
48
|
// Look picture
|
|
@@ -90,6 +91,7 @@ const questionTransformHandlers = {
|
|
|
90
91
|
GN_SPEAKING_INTERVIEW: transformGNSpeakingInterview,
|
|
91
92
|
WORD_FILL_STRUCTURED_FORM: transformWordFillStructuredForm,
|
|
92
93
|
CROSSWORD_PUZZLE: transformCrosswordPuzzle,
|
|
94
|
+
FIND_WORDS_IN_MATRIX: transformFindWordsInMatrix,
|
|
93
95
|
};
|
|
94
96
|
/**
|
|
95
97
|
* Transform frontend question format to API format.
|
|
@@ -29,7 +29,7 @@ export declare enum StudentSelectionType {
|
|
|
29
29
|
}
|
|
30
30
|
export type ResultStatus = 'PENDING' | 'PARTIAL_GRADED' | 'GRADED';
|
|
31
31
|
export type StudentStatus = 'NOT_STARTED' | 'IN_PROGRESS' | 'SUBMITTED';
|
|
32
|
-
export type QuestionType = 'FILL_IN_BLANK' | 'TRUE_FALSE' | 'MATCHING' | 'ORDERING' | 'LISTENING' | 'COLORING' | 'ESSAY' | 'LISTEN_AND_FILL_IN_THE_BLANK_WITH_IMAGE' | 'LISTEN_AND_TICK_ANSWER' | 'LISTEN_AND_FILL_NAME_NUMBER' | 'LISTENING_FILL_BLANK' | 'LISTENING_COLOR' | 'TICK_TRUE_OR_FALSE' | 'TICK_YES_OR_NO' | 'READING_TICK_CROSS' | 'ARRANGE_LETTERS_INTO_WORDS' | 'READ_PASSAGE_AND_COMPLETE_STORY' | 'CLOZE_TEST_WITH_TICK_BOX' | 'READ_AND_CHOOSE_APPROPRIATE_WORD' | 'WRITE_SHORT_PARAGRAPH' | 'LABEL_THE_PICTURE' | 'READING_LETTER_ARRANGE' | 'READING_PASSAGE_FILL' | 'FILL_BLANK' | 'FILL_MISSING_WORDS_IN_GRID' | 'LOOK_PICTURE_CHOOSE_CORRECT_ANSWER' | 'LOOK_PICTURE_FILL_BLANK_CHOOSE_ANSWER' | 'LOOK_PICTURE_FILL_WORD_HINT' | 'LABEL_THE_PICTURE' | 'READ_AND_COLOR_OBJECTS' | 'IMAGE_OBJECT_MATCHING' | 'READ_PASSAGE_AND_ANSWER_QUESTIONS' | 'CHOOSE_THE_CORRECT_ANSWER' | 'CHOOSE_THE_CORRECT_ANSWER_GROUP' | 'TRUE_FALSE_GROUP' | 'CROSS_OUT_WORD_GROUP' | 'SPONTANEOUS_QA_GROUP' | 'WORD_ORDER_AND_MATCH_GROUP' | 'WRITE_A_SHORT_LETTER' | 'WRITE_CORRECT_VERB_FORM' | 'CHOOSE_CORRECT_ADJECTIVE' | 'ANSWER_THE_QUESTION' | 'ANSWER_THE_QUESTION_GROUP' | 'WORD_ORDERING' | 'WORD_FILL_PARAGRAPH' | 'MATCH_BY_WRITING_ANSWER' | 'WRITE_SENTENCES' | 'LISTEN_AND_CHOOSE_FROM_ANSWER_GROUP' | 'LISTEN_AND_CHOOSE_OBJECTS_IN_SCENE' | 'LISTEN_AND_DRAG_OBJECTS_INTO_SCENE' | 'LISTEN_AND_SPEAK_ANSWER' | 'LISTEN_AND_SPEAK_IMAGE_GROUP' | 'LISTEN_AND_SPEAK_QUESTION_LIST' | 'LISTEN_AND_SPEAK_COMPARE_IMAGES' | 'LISTEN_AND_SPEAK_WITH_STORY_IMAGES' | 'LISTEN_AND_SPEAK_ODD_ONE_OUT' | 'LISTEN_AND_SPEAK_INFO_EXCHANGE' | 'READ_DISPLAYED_CONTENT' | 'SPEAKING_DESCRIBE_IMAGE' | 'SPONTANEOUS_QA' | 'SPEAKING_CONVERSATION' | 'GN_SPEAKING_INTERVIEW' | 'SPEAKING_CUE_CARD' | 'WORD_FILL_STRUCTURED_FORM' | 'CROSSWORD_PUZZLE';
|
|
32
|
+
export type QuestionType = 'FILL_IN_BLANK' | 'TRUE_FALSE' | 'MATCHING' | 'ORDERING' | 'LISTENING' | 'COLORING' | 'ESSAY' | 'LISTEN_AND_FILL_IN_THE_BLANK_WITH_IMAGE' | 'LISTEN_AND_TICK_ANSWER' | 'LISTEN_AND_FILL_NAME_NUMBER' | 'LISTENING_FILL_BLANK' | 'LISTENING_COLOR' | 'TICK_TRUE_OR_FALSE' | 'TICK_YES_OR_NO' | 'READING_TICK_CROSS' | 'ARRANGE_LETTERS_INTO_WORDS' | 'READ_PASSAGE_AND_COMPLETE_STORY' | 'CLOZE_TEST_WITH_TICK_BOX' | 'READ_AND_CHOOSE_APPROPRIATE_WORD' | 'WRITE_SHORT_PARAGRAPH' | 'LABEL_THE_PICTURE' | 'READING_LETTER_ARRANGE' | 'READING_PASSAGE_FILL' | 'FILL_BLANK' | 'FILL_MISSING_WORDS_IN_GRID' | 'LOOK_PICTURE_CHOOSE_CORRECT_ANSWER' | 'LOOK_PICTURE_FILL_BLANK_CHOOSE_ANSWER' | 'LOOK_PICTURE_FILL_WORD_HINT' | 'LABEL_THE_PICTURE' | 'READ_AND_COLOR_OBJECTS' | 'IMAGE_OBJECT_MATCHING' | 'READ_PASSAGE_AND_ANSWER_QUESTIONS' | 'CHOOSE_THE_CORRECT_ANSWER' | 'CHOOSE_THE_CORRECT_ANSWER_GROUP' | 'TRUE_FALSE_GROUP' | 'CROSS_OUT_WORD_GROUP' | 'SPONTANEOUS_QA_GROUP' | 'WORD_ORDER_AND_MATCH_GROUP' | 'WRITE_A_SHORT_LETTER' | 'WRITE_CORRECT_VERB_FORM' | 'CHOOSE_CORRECT_ADJECTIVE' | 'ANSWER_THE_QUESTION' | 'ANSWER_THE_QUESTION_GROUP' | 'WORD_ORDERING' | 'WORD_FILL_PARAGRAPH' | 'MATCH_BY_WRITING_ANSWER' | 'WRITE_SENTENCES' | 'LISTEN_AND_CHOOSE_FROM_ANSWER_GROUP' | 'LISTEN_AND_CHOOSE_OBJECTS_IN_SCENE' | 'LISTEN_AND_DRAG_OBJECTS_INTO_SCENE' | 'LISTEN_AND_SPEAK_ANSWER' | 'LISTEN_AND_SPEAK_IMAGE_GROUP' | 'LISTEN_AND_SPEAK_QUESTION_LIST' | 'LISTEN_AND_SPEAK_COMPARE_IMAGES' | 'LISTEN_AND_SPEAK_WITH_STORY_IMAGES' | 'LISTEN_AND_SPEAK_ODD_ONE_OUT' | 'LISTEN_AND_SPEAK_INFO_EXCHANGE' | 'READ_DISPLAYED_CONTENT' | 'SPEAKING_DESCRIBE_IMAGE' | 'SPONTANEOUS_QA' | 'SPEAKING_CONVERSATION' | 'GN_SPEAKING_INTERVIEW' | 'SPEAKING_CUE_CARD' | 'WORD_FILL_STRUCTURED_FORM' | 'CROSSWORD_PUZZLE' | 'FIND_WORDS_IN_MATRIX';
|
|
33
33
|
export type Level = 'Pre-A1' | 'A1' | 'A2' | 'B1' | 'B2' | 'C1' | 'C2';
|
|
34
34
|
export type Difficulty = 'EASY' | 'MEDIUM' | 'HARD';
|
|
35
35
|
export type Skill = 'LISTENING' | 'READING' | 'WRITING' | 'SPEAKING';
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FIND_WORDS_IN_MATRIX Question Type Interfaces (SDK)
|
|
3
|
+
*
|
|
4
|
+
* Supported types:
|
|
5
|
+
* - 'WORD_BANK': Standard word search with given word bank (default).
|
|
6
|
+
* - 'CATEGORIZE': Word search where words are categorized under headings (e.g. Plants vs Animals).
|
|
7
|
+
*/
|
|
8
|
+
import { QuestionBankSettings } from './choose-the-correct-answer';
|
|
9
|
+
export type FindWordsInMatrixType = 'WORD_BANK' | 'CATEGORIZE';
|
|
10
|
+
export interface MatrixCellCoord {
|
|
11
|
+
row: number;
|
|
12
|
+
col: number;
|
|
13
|
+
}
|
|
14
|
+
export interface CategoryHeadingItem {
|
|
15
|
+
id: string;
|
|
16
|
+
name: string;
|
|
17
|
+
color?: string;
|
|
18
|
+
}
|
|
19
|
+
export interface WordBankItem {
|
|
20
|
+
id: string;
|
|
21
|
+
word: string;
|
|
22
|
+
isExample?: boolean;
|
|
23
|
+
categoryId?: string;
|
|
24
|
+
}
|
|
25
|
+
export interface ExampleSelection {
|
|
26
|
+
wordId: string;
|
|
27
|
+
categoryId?: string;
|
|
28
|
+
path: MatrixCellCoord[];
|
|
29
|
+
}
|
|
30
|
+
export interface FindWordsInMatrixContent {
|
|
31
|
+
type?: FindWordsInMatrixType;
|
|
32
|
+
title?: string;
|
|
33
|
+
gridSize: {
|
|
34
|
+
rows: number;
|
|
35
|
+
cols: number;
|
|
36
|
+
};
|
|
37
|
+
grid: string[][];
|
|
38
|
+
categories?: CategoryHeadingItem[];
|
|
39
|
+
wordBank: WordBankItem[];
|
|
40
|
+
exampleSelection?: ExampleSelection;
|
|
41
|
+
}
|
|
42
|
+
export interface CorrectWordItem {
|
|
43
|
+
wordId: string;
|
|
44
|
+
word?: string;
|
|
45
|
+
categoryId?: string;
|
|
46
|
+
path: MatrixCellCoord[];
|
|
47
|
+
}
|
|
48
|
+
export interface FindWordsInMatrixCorrectAnswer {
|
|
49
|
+
words: CorrectWordItem[];
|
|
50
|
+
caseSensitive?: boolean;
|
|
51
|
+
}
|
|
52
|
+
export interface StudentWordSelectionItem {
|
|
53
|
+
wordId?: string;
|
|
54
|
+
word?: string;
|
|
55
|
+
categoryId?: string;
|
|
56
|
+
path: MatrixCellCoord[];
|
|
57
|
+
}
|
|
58
|
+
export interface FindWordsInMatrixAPIPayload {
|
|
59
|
+
id?: string;
|
|
60
|
+
questionType: 'FIND_WORDS_IN_MATRIX';
|
|
61
|
+
content: FindWordsInMatrixContent;
|
|
62
|
+
correctAnswer: FindWordsInMatrixCorrectAnswer;
|
|
63
|
+
points: number;
|
|
64
|
+
explanation?: string;
|
|
65
|
+
questionNumber: number;
|
|
66
|
+
partId?: string;
|
|
67
|
+
partNo?: number;
|
|
68
|
+
addToQuestionBank?: boolean;
|
|
69
|
+
questionBank?: QuestionBankSettings;
|
|
70
|
+
}
|
|
71
|
+
export type FindWordsInMatrixLocalStorage = Omit<FindWordsInMatrixAPIPayload, 'addToQuestionBank' | 'questionBank'>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FIND_WORDS_IN_MATRIX Question Type Interfaces (SDK)
|
|
3
|
+
*
|
|
4
|
+
* Supported types:
|
|
5
|
+
* - 'WORD_BANK': Standard word search with given word bank (default).
|
|
6
|
+
* - 'CATEGORIZE': Word search where words are categorized under headings (e.g. Plants vs Animals).
|
|
7
|
+
*/
|
|
8
|
+
export {};
|