|
1 | 1 | # @pie-element/mc-populated-blank |
2 | 2 |
|
3 | | -Svelte 5 PIE element: the learner picks a **multiple-choice** option and that choice **fills a blank** inside an HTML **template**. |
| 3 | +Svelte 5 PIE element where the learner picks a **multiple-choice** option and that choice **fills a blank** in a sentence/template. |
| 4 | + |
| 5 | +This element is the PIE counterpart for Star Learnosity CQT "populated blank" interactions. The CQT family had several published `custom_type` flavors, but they are all variants of the same base interaction: |
| 6 | + |
| 7 | +- one selected choice |
| 8 | +- one correctness key |
| 9 | +- selected choice rendered into a blank target |
| 10 | +- optional audio/transcript support |
| 11 | + |
| 12 | +## What the original CQT flavors mean |
| 13 | + |
| 14 | +The historical Learnosity CQT names mostly describe layout/stimulus differences, not different scoring logic: |
| 15 | + |
| 16 | +- `sel_vic`: sentence-style vocabulary in context, with audio/transcript support |
| 17 | +- `sr-vic`: sentence-style vocabulary in context, typically no audio button |
| 18 | +- `sel_r1-g_plusggg`: lead token before blank (`before_cloze_1`) plus choice set |
| 19 | +- `sel_r1-_gplusggg`: blank with a shorter/token-focused stem arrangement |
| 20 | +- `sel_r1-_plusggg`: audio + choices only (no blank; modeled as audio-only mode) |
| 21 | +- `sel_r1-gg_plusggg`: token-sequence variant with larger glyph-like tokens |
| 22 | +- `sel_r1-_ggplusggg`: blank appears before trailing tokens (`after_cloze_*`) |
| 23 | +- `sel_r1-s3_plusggg`: stimulus-heavy variant (often image/sentence block + blank + choices) |
| 24 | + |
| 25 | +The shared behavior across these flavors is now represented by one element with configuration, instead of one element per flavor. |
| 26 | + |
| 27 | +## Flavor to model mapping (quick defaults) |
| 28 | + |
| 29 | +Use this as a practical starting point when mapping Learnosity CQT payloads into `mc-populated-blank` models. |
| 30 | + |
| 31 | +| Learnosity `custom_type` | Typical layout meaning | Suggested `interactionMode` | Suggested `choiceMode` | Template hint | |
| 32 | +| --- | --- | --- | --- | --- | |
| 33 | +| `sel_vic` | sentence cloze with audio/transcript | `populate_blank` | `text` | `<p>{before} {{blank}} {after}</p>` | |
| 34 | +| `sr-vic` | sentence cloze without listen button | `populate_blank` | `text` | `<p>{before} {{blank}} {after}</p>` | |
| 35 | +| `sel_r1-g_plusggg` | lead token before blank | `populate_blank` | `text` | `<p>{before_cloze_1} {{blank}}</p>` | |
| 36 | +| `sel_r1-_gplusggg` | short stem + blank | `populate_blank` | `text` | `<p>{before/after segments around {{blank}}}</p>` | |
| 37 | +| `sel_r1-_plusggg` | audio + choices only (no blank) | `audio_mc_only` | `text` | no blank token in template | |
| 38 | +| `sel_r1-gg_plusggg` | token-sequence style before blank | `populate_blank` | `text` | `<p>{before_1}{before_2} {{blank}}</p>` | |
| 39 | +| `sel_r1-_ggplusggg` | blank before trailing tokens | `populate_blank` | `text` | `<p>{{blank}} {after_1}{after_2}</p>` | |
| 40 | +| `sel_r1-s3_plusggg` | stimulus-heavy/image-first variant | `populate_blank` | `text` or `image` | include stimulus in `prompt`/`sentenceHtml`; keep single blank in `template` | |
| 41 | + |
| 42 | +Notes: |
| 43 | + |
| 44 | +- `choiceMode` should be `image` only when distractors are image choices; otherwise use `text`. |
| 45 | +- Current model contract is single-blank for `populate_blank`; dual-cloze source shapes are normalized to one `{{blank}}`. |
| 46 | +- `correctChoiceId` should always map from Learnosity `valid_response.name` (`distractor_n` -> `cN`). |
| 47 | +- Layout defaults are tuned from original CQT visual baselines, but they are not fixed: override through `model.layoutLimits` when host/theme requirements differ. |
4 | 48 |
|
5 | 49 | ## Authoring model |
6 | 50 |
|
7 | 51 | - **`prompt`** (optional) and **`promptEnabled`** |
8 | 52 | - **`template`**: HTML string containing exactly one literal `{{blank}}` token |
| 53 | +- **`interactionMode`**: `populate_blank` | `audio_mc_only` |
9 | 54 | - **`choiceMode`**: `text` | `image` |
10 | 55 | - **`choices`**: `{ id, labelHtml? }` or `{ id, imageUrl, imageAlt }` per mode |
11 | 56 | - **`correctChoiceId`** |
12 | | -- **`hasAudio`**, **`audioUrl`**, **`audioTranscript`** (optional) |
| 57 | +- **`hasAudio`**, **`audioUrl`**, **`audioTranscript`** (`audioUrl` required when `hasAudio=true`) |
| 58 | +- **`autoplayAudioEnabled`**, **`completeAudioEnabled`** (optional integration flags) |
| 59 | +- **`layoutLimits`** (optional): numeric visual constraints; defaults are based on current CQT parity behavior and can be overridden per item |
| 60 | +- **`layoutProfilePresets`** (optional): named preset map by `layoutProfile`; use profile as a template and override with `layoutLimits` |
| 61 | +- **`audioButtonSkin`** / **`audioButtonSkinsByLocale`** (optional): override listen-button skin URLs |
| 62 | +- **`uiText`** (optional): override labels/messages (show/hide correct, answer choices, autoplay prompt, transcript label, missing-audio message) |
| 63 | + |
| 64 | +### `layoutLimits` keys (all optional, positive numbers) |
| 65 | + |
| 66 | +- `blankStandaloneWidthRem` |
| 67 | +- `blankWideWidthRem` |
| 68 | +- `blankUnderlineWidthPx` |
| 69 | +- `blankUnderlineWideWidthPx` |
| 70 | +- `horizontalChoiceWidthPx` |
| 71 | +- `horizontalChoiceWidthVw` |
| 72 | +- `horizontalChoiceTileMinHeightRem` |
| 73 | +- `horizontalChoiceContentMinHeightRem` |
| 74 | +- `selectedImageMaxHeightRem` |
| 75 | +- `choiceImageMaxHeightRem` |
| 76 | +- `listenButtonSizePx` |
| 77 | +- `stimulusMinColumnPx` |
| 78 | +- `textMinColumnPx` |
| 79 | +- `legendMaxChars` |
| 80 | +- `choiceGroupGapRem` |
| 81 | +- `choiceRowGapRem` |
| 82 | +- `toggleButtonGapRem` |
| 83 | +- `horizontalChoiceRadioTopMarginRem` |
| 84 | +- `audioBlankTemplateMarginTopRem` |
| 85 | +- `audioBlankTemplateMarginBottomRem` |
| 86 | +- `stimulusGridColumnGapRem` |
| 87 | +- `stimulusGridRowGapRem` |
| 88 | +- `stimulusSentenceMarginTopRem` |
| 89 | +- `stimulusChoicesMarginTopRem` |
| 90 | +- `tokenGridColumnGapRem` |
| 91 | +- `tokenGridRowGapRem` |
| 92 | +- `tokenTemplateMarginTopRem` |
| 93 | +- `tokenInlineTokenGapRem` |
| 94 | +- `tokenChoicesMarginTopRem` |
| 95 | +- `inlineGridColumnGapRem` |
| 96 | +- `inlineGridRowGapRem` |
| 97 | +- `inlineTemplateMarginTopRem` |
| 98 | +- `inlineChoicesMarginTopRem` |
13 | 99 |
|
14 | 100 | ## Session |
15 | 101 |
|
16 | 102 | - **`choiceId`**: selected choice id |
17 | 103 |
|
| 104 | +## Implementation hints |
| 105 | + |
| 106 | +- **Controller invariants:** in `populate_blank`, template must contain exactly one `{{blank}}`; in `audio_mc_only`, template must not contain `{{blank}}`. |
| 107 | +- **Choice normalization:** choices are polymorphic by `choiceMode` (text via `labelHtml`, image via `imageUrl`/`imageAlt`). |
| 108 | +- **Delivery rendering:** template is split around `{{blank}}`; selected choice content is rendered into the blank slot. |
| 109 | +- **Layout limits are model-driven:** delivery reads `model.layoutLimits` (blank widths/underline widths, choice tile sizing, image max heights, listen button size, layout column minimums); defaults are CQT-informed but overrideable. |
| 110 | +- **Evaluate mode behavior:** when evaluate/correct-answer mode is enabled, delivery can render `correctChoiceId` in the blank/choice state. |
| 111 | +- **Audio error behavior:** no TTS fallback is used; when `hasAudio=true` and no playable `audioUrl` is provided, delivery shows an explicit error message (configurable via `uiText.audioResourceUnavailable`). |
| 112 | +- **Print parity:** print view mirrors prompt/template/choice presentation with the same blank-token contract. |
| 113 | + |
| 114 | +## Theming hooks (`pie-*` classes) |
| 115 | + |
| 116 | +Delivery now exposes stable `pie-*` classes so hosts can theme this element with the same class-oriented approach used by other PIE elements. |
| 117 | + |
| 118 | +- Root/container: `pie-element`, `pie-element-mc-populated-blank`, `pie-delivery-root` |
| 119 | +- Prompt/audio/template: `pie-prompt`, `pie-audio-container`, `pie-audio-player`, `pie-audio-transcript`, `pie-template-line`, `pie-sentence-line` |
| 120 | +- Blank display: `pie-blank-slot`, `pie-blank-slot-standalone`, `pie-blank-value`, `pie-blank-image` |
| 121 | +- Choice group: `pie-choices-fieldset`, `pie-choices-legend`, `pie-choices` |
| 122 | +- Choice rows/items: `pie-choice`, `pie-choice-horizontal`, `pie-choice-selected`, `pie-choice-label`, `pie-choice-image` |
| 123 | +- Choice controls: `pie-choice-radio`, `pie-choice-radio-inline`, `pie-choice-radio-bottom` |
| 124 | +- Evaluate/toggle feedback: `pie-toggle-correct-answer`, `pie-result-feedback`, `pie-choice-feedback-correct`, `pie-choice-feedback-incorrect` |
| 125 | + |
18 | 126 | ## Builds |
19 | 127 |
|
20 | 128 | Same layout as `@pie-element/simple-cloze`: `delivery`, `controller`, `author`, `print`, plus IIFE bundle for script-tag loading. |
|
0 commit comments