import ExpFrameBaseComponent from '../exp-frame-base/component';
import ExperimentParser from '../../utils/parse-experiment';
/**
* @module exp-player
* @submodule frames
*/
/**
*
* Frame that allows you to specify a list of possible frames to show, plus an index or
* list of indices of which ones to actually show. The frame(s) will be inserted into the
* sequence of frames for this study on the fly, so that you can use a custom
* <a href="../classes/Exp-frame-base.html#property_generateProperties" class="crosslink">generateProperties</a>
* function to select which frame(s) to show.
*
*
* This frame serves as a wrapper for the randomizer <a href="../classes/Select.html" class="crosslink">select</a>,
* which is evaluated during experiment parsing and cannot be modified on the fly.
*
*
* For more information about making study behavior conditional on data collected,
* see <a href="https://lookit.readthedocs.io/en/develop/researchers-create-experiment.html#conditional-logic">the Lookit docs</a>.
*
*
* Example usage:
```json
"study-procedure": {
"kind": "exp-frame-select",
"frameOptions": [
{
"kind": "exp-lookit-text",
"blocks": [
{
"emph": true,
"text": "Cats are great"
},
{
"text": "We are measuring how much your child loves cats now. Beep boop!"
}
]
},
{
"kind": "exp-lookit-text",
"blocks": [{
"emph": true,
"text": "Your child is not eligible for this study"
},
{
"text": "Either you do not have any cats or your child does not love cats."
}
]
}
],
"generateProperties": "function(expData, sequence, child, pastSessions) {var formData = expData['0-eligibility-survey'].formData; if (formData.nCats >= 1 && formData.loveCats == 'yes') { console.log('eligible'); return { 'whichFrames': 0, 'ELIGIBLE': true } } else { console.log('ineligible'); return { 'whichFrames': 1, 'ELIGIBLE': false } } }"
}
* ```
*
*
* **Warning:** to avoid unpredictable behavior, this frame does not itself use any
* <a href="../classes/Exp-frame-base.html#property_selectNextFrame" class="crosslink">selectNextFrame</a> passed to it.
* (Frames within the `frameOptions` list are welcome to make use of `selectNextFrame`, though!)
*
*
* Data will be stored for this frame so that any ``generatedProperties`` are available
* for future use; however, it will proceed immediately upon loading to the first frame
* that is specified (or the next frame in the original sequence, if it turns out that `whichFrames` is an empty
* list).
*
*
* In `expData`, the frame keys for all frames generated by this frame will be prefixed
* by this frame's ID, with an index within `whichFrames` appended to the end of the ID.
* For instance, if this frame's ID is `1-study-procedure`, and it generates three frames,
* we would have keys `1-study-procedure`, `1-study-procedure-0`, `1-study-procedure-1`, and
* `1-study-procedure-2`.
*
*
* @class Exp-frame-select
* @extends Exp-frame-base
*
*/
export default ExpFrameBaseComponent.extend({
type: 'exp-frame-select',
whichFrames: -1,
frameSchemaProperties: {
/**
* List of frames that can be created by this randomizer. Each frame is an
* object with any necessary frame-specific properties specified. The
* 'kind' of frame can be specified either here (per frame) or in
* commonFrameProperties. If a property is defined for a given frame both
* in this frame list and in commonFrameProperties, the value in the frame
* list will take precedence.
*
* (E.g., you could include 'kind': 'normal-frame' in
* commmonFrameProperties, but for a single frame in frameOptions, include
* 'kind': 'special-frame'.)
*
* @property {Object[]} frameOptions
*/
frameOptions: {
type: 'array',
items: {
type: 'object'
},
default: []
},
/**
* Object describing common parameters to use in EVERY frame created
* by this randomizer. Parameter names and values are as described in
* the documentation for the frameType used.
*
* @property {Object} commonFrameProperties
*/
commonFrameProperties: {
type: 'object',
default: {}
},
/**
* Index or indices (0-indexed) within frameOptions to actually use. This can be either a number
* (e.g., 0 or 1 to use the first or second option respectively) or an array providing
* an ordered list of indices to use (e.g., [0, 1] or [1, 0] to use the first then
* second or second then first options, respectively). All indices must be integers
* in [0, frameOptions.length).
*
* If not provided or -1, the entire frameOptions list is used in order. (If empty
* list is provided, however, that is respected and no frames are inserted by this
* randomizer.)
*
* @property {Number} whichFrames
*/
whichFrames: {
type: 'number',
default: -1
}
},
meta: {
data: {
type: 'object',
properties: {
}
}
},
didReceiveAttrs() {
this._super(...arguments);
// Convert current frame (w/ possibly updated parameters based on generateProperties)
// to a single 'select' randomizer frame.
var equivalentRandomizer = {
'kind': 'choice',
'sampler': 'select',
'whichFrames': this.get('whichFrames') == -1 ? [...this.get('frameOptions').keys()] : this.get('whichFrames'),
'frameOptions': this.get('frameOptions'),
'commonFrameProperties': this.get('commonFrameProperties')
};
this.set('whichFrames', -1);
var id = this.get('id');
var parser = new ExperimentParser({
structure: {
'frames': {
[id]: equivalentRandomizer
},
'sequence': [
id
]
},
pastSessions: this.parentView.get('pastSessions').toArray()
});
const prependFrameInds = false;
var [frameConfigs, conditions] = parser.parse(prependFrameInds);
var frames = this.parentView.get('frames');
frames.splice(this.get('frameIndex') + 1, 0, ...frameConfigs);
this.parentView.set('frames', frames);
var existingConditions = this.parentView.get('conditions');
if (existingConditions) {
Object.assign(existingConditions, conditions);
}
this.parentView.set('conditions', existingConditions);
},
didRender() {
this._super(...arguments);
this.send('next');
}
});