Update README and App.vue with detailed project specifications and input schema
This commit is contained in:
parent
b5926e868f
commit
d6e8ca4068
131
README.md
131
README.md
@ -1,29 +1,124 @@
|
|||||||
# js-exform
|
## Introduction
|
||||||
|
|
||||||
This template should help get you started developing with Vue 3 in Vite.
|
This project is to develop a Vue 3 single page questionnaire application to be embedded in online psychology experiments. Demo pages are hosted to show how it looks like:
|
||||||
|
- [Standard](https://js-exform.pages.dev/demo)
|
||||||
|
- [Dark mode](https://js-exform.pages.dev/demo-dark)
|
||||||
|
- [Chinese version](https://js-exform.pages.dev/demo-cn)
|
||||||
|
|
||||||
## Recommended IDE Setup
|
This project is still under active development and could be very unstable (due to skill issues).
|
||||||
|
|
||||||
[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur).
|
The following parts of the documentation are generated by `Claude-3.7-Sonnet`.
|
||||||
|
|
||||||
## Customize configuration
|
## Data Transport
|
||||||
|
|
||||||
See [Vite Configuration Reference](https://vite.dev/config/).
|
The questionnaire component receives input via the `window.postMessage` API. The parent window should post a message with the following structure:
|
||||||
|
|
||||||
## Project Setup
|
```javascript
|
||||||
|
window.postMessage({
|
||||||
|
type: 'spec',
|
||||||
|
title: 'Your Questionnaire Title',
|
||||||
|
items: [...], // Array of question items
|
||||||
|
settings: {...} // Configuration options
|
||||||
|
}, '*');
|
||||||
|
```
|
||||||
|
|
||||||
|
## Input Schema
|
||||||
|
|
||||||
|
### Root Object
|
||||||
|
|
||||||
|
| Field | Type | Required | Description |
|
||||||
|
|-------|------|----------|-------------|
|
||||||
|
| type | string | Yes | Must be 'spec' |
|
||||||
|
| title | string | Yes | Main title of the questionnaire |
|
||||||
|
| items | array | Yes | Array of question items |
|
||||||
|
| settings | object | No | Configuration options |
|
||||||
|
|
||||||
|
### Item Object
|
||||||
|
|
||||||
|
Each item in the `items` array represents a question with the following structure:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
type: 'text', // 'text', 'radio', 'checkbox', 'scale', 'display'
|
||||||
|
title: 'Question text',
|
||||||
|
desc: 'Optional description text with HTML support',
|
||||||
|
key: 'unique_identifier', // Optional, defaults to title
|
||||||
|
optTexts: ['Option 1', 'Option 2'], // For 'radio', 'checkbox', 'scale'
|
||||||
|
optValues: ['value1', 'value2'], // For 'radio', 'checkbox', 'scale'
|
||||||
|
required: true, // Whether answer is required
|
||||||
|
minOpts: 1, // For 'checkbox', minimum options to select
|
||||||
|
maxOpts: 3 // For 'checkbox', maximum options to select
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Item Fields
|
||||||
|
|
||||||
|
| Field | Type | Required | Description |
|
||||||
|
|-------|------|----------|-------------|
|
||||||
|
| type | string | Yes | Question type: 'text', 'radio', 'checkbox', 'scale', or 'display' |
|
||||||
|
| title | string | Yes | Question text |
|
||||||
|
| desc | string | No | Additional descriptive text (supports HTML) |
|
||||||
|
| key | string | No | Unique identifier (defaults to title if not provided) |
|
||||||
|
| optTexts | array | Conditional | Array of option texts for 'radio', 'checkbox', 'scale' |
|
||||||
|
| optValues | array | Conditional | Array of option values for 'radio', 'checkbox', 'scale' |
|
||||||
|
| required | boolean | No | Whether an answer is required (default: false) |
|
||||||
|
| minOpts | number | No | Minimum options to select for 'checkbox' (default: 1) |
|
||||||
|
| maxOpts | number | No | Maximum options to select for 'checkbox' (default: total options) |
|
||||||
|
|
||||||
|
### Settings Object
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
allowBack: true, // Allow navigation to previous questions
|
||||||
|
allowAutoNext: true, // Auto-advance after selection for radio/scale
|
||||||
|
darkMode: false, // Visual theme
|
||||||
|
lang: 'en-US' // Language code
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Question Types
|
||||||
|
|
||||||
|
- **text**: Single-line text input
|
||||||
|
- **radio**: Single-choice selection with radio buttons
|
||||||
|
- **checkbox**: Multiple-choice selection with checkboxes
|
||||||
|
- **scale**: Slider scale with labeled endpoints
|
||||||
|
- **display**: Information display with no input required
|
||||||
|
|
||||||
|
## Response Format
|
||||||
|
|
||||||
|
When the questionnaire is completed, the component sends a message to the parent window:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
type: 'response',
|
||||||
|
started: 1646120000000, // Timestamp when questionnaire started
|
||||||
|
ended: 1646121000000, // Timestamp when questionnaire completed
|
||||||
|
results: [
|
||||||
|
{
|
||||||
|
title: 'Question text',
|
||||||
|
key: 'question_key',
|
||||||
|
type: 'question_type',
|
||||||
|
answer: 'user_response',
|
||||||
|
answerText: 'Text representation of response',
|
||||||
|
answerValue: 'Value representation of response',
|
||||||
|
refilled: false, // Whether the answer was changed
|
||||||
|
responseTime: 5000 // Time spent on question in milliseconds
|
||||||
|
},
|
||||||
|
// Additional question results...
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
Please refer to source code of demo files.
|
||||||
|
|
||||||
|
## For developers
|
||||||
|
|
||||||
|
To modify or build the component, simply follow the standard routine:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
npm install
|
npm install
|
||||||
```
|
|
||||||
|
|
||||||
### Compile and Hot-Reload for Development
|
|
||||||
|
|
||||||
```sh
|
|
||||||
npm run dev
|
npm run dev
|
||||||
```
|
|
||||||
|
|
||||||
### Compile and Minify for Production
|
|
||||||
|
|
||||||
```sh
|
|
||||||
npm run build
|
npm run build
|
||||||
```
|
```
|
12
src/App.vue
12
src/App.vue
@ -4,18 +4,6 @@ import { isProxy } from 'vue';
|
|||||||
import { sprintf } from 'sprintf-js';
|
import { sprintf } from 'sprintf-js';
|
||||||
import lang from './lang.js';
|
import lang from './lang.js';
|
||||||
|
|
||||||
/*
|
|
||||||
* Specification of item data structure:
|
|
||||||
* {
|
|
||||||
* type: string, // 'text', 'radio', 'checkbox', 'scale'
|
|
||||||
* title: string,
|
|
||||||
* optTexts: string[], // only for 'radio', 'checkbox', 'scale'
|
|
||||||
* optValues: string[], // only for 'radio', 'checkbox', 'scale'
|
|
||||||
* required: boolean, // whether the user must answer the question
|
|
||||||
* answer: string, // user's answer, appended after user submits
|
|
||||||
* refilled: boolean, // whether the user refilled the answer, appended after user submits
|
|
||||||
* }
|
|
||||||
*/
|
|
||||||
const ITEM_TYPES = ['text', 'radio', 'checkbox', 'scale', 'display'];
|
const ITEM_TYPES = ['text', 'radio', 'checkbox', 'scale', 'display'];
|
||||||
function isValidItem({ type, title, optTexts, optValues = null }) {
|
function isValidItem({ type, title, optTexts, optValues = null }) {
|
||||||
if (!title || !ITEM_TYPES.includes(type)) {
|
if (!title || !ITEM_TYPES.includes(type)) {
|
||||||
|
Loading…
Reference in New Issue
Block a user