Show:

File: app/components/exp-lookit-instructions/component.js

import Em from 'ember';

import layout from './template';
import ExpFrameBaseComponent from '../exp-frame-base/component';
import VideoRecord from '../../mixins/video-record';

let {
    $
} = Em;

/**
 * @module exp-player
 * @submodule frames
 */

/**
 * A frame to display instructions to the user. The user's webcam may optionally be
 * displayed, and audio and video clips may be included in the instructions (and may be
 * required to be played before moving on).
 *
 * Each element of the 'blocks' parameter is rendered using {{#crossLink "Exp-text-block"}}{{/crossLink}}.

```json
 "frames": {
        "instructions": {
            "kind": "exp-lookit-instructions",
            "blocks": [
                {
                    "title": "Parent's role",
                    "listblocks": [
                        {
                            "text": "Follow instructions"
                        },
                        {
                            "text": "Only do each joke once"
                        }
                    ]
                },
                {
                    "text": "It's important that we can see you",
                    "image": {
                        "alt": "Father holding child looking over his shoulder",
                        "src": "https://s3.amazonaws.com/lookitcontents/exp-physics/OverShoulder.jpg"
                    },
                    "title": "Camera position"
                },
                {
                    "text": "Here's some audio you have to play",
                    "title": "Test",
                    "mediaBlock": {
                        "text": "You should hear 'Ready to go?'",
                        "isVideo": false,
                        "sources": [
                            {
                                "src": "https://s3.amazonaws.com/lookitcontents/exp-physics-final/audio/ready.mp3",
                                "type": "audio/mp3"
                            },
                            {
                                "src": "https://s3.amazonaws.com/lookitcontents/exp-physics-final/audio/ready.ogg",
                                "type": "audio/ogg"
                            }
                        ],
                        "mustPlay": true,
                        "warningText": "Please try playing the sample audio."
                    }
                },
                {
                    "text": "Here's a video you don't have to play!",
                    "title": "Test",
                    "mediaBlock": {
                        "text": "Look at that.",
                        "isVideo": true,
                        "sources": [
                            {
                                "src": "https://s3.amazonaws.com/lookitcontents/exp-physics-final/examples/7_control_same.mp4",
                                "type": "video/mp4"
                            },
                            {
                                "src": "https://s3.amazonaws.com/lookitcontents/exp-physics-final/examples/7_control_same.webm",
                                "type": "video/webm"
                            }
                        ],
                        "mustPlay": false
                    }
                }
            ],
            "showWebcam": true,
            "webcamBlocks": [
                {
                    "title": "Some webcam instructions",
                    "listblocks": [
                        {
                            "text": "Like this!"
                        },
                        {
                            "text": "Be careful your webcam does not have tape over it"
                        }
                    ]
                }
            ],
            "nextButtonText": "Next"
        }
 }

 * ```
 * @class Exp-lookit-instructions
 * @extends Exp-frame-base
 * @extends Video-record
 */

export default ExpFrameBaseComponent.extend(VideoRecord, {
    layout: layout,
    type: 'exp-lookit-instructions',
    doUseCamera: Em.computed.alias('showWebcam'),
    frameSchemaProperties: {

        // Note: don't display the following in the docs; they're not used because startRecordingAutomatically is
        // false.

        /**
         * @property {Boolean} showWaitForRecordingMessage
         * @private
         */

        /**
         * @property {Boolean} waitForRecordingMessage
         * @private
         */

        /**
         * @property {Boolean} waitForRecordingMessageColor
         * @private
         */

        /**
         * @property {Boolean} showWaitForUploadMessage
         * @private
         */

        /**
         * @property {Boolean} waitForUploadMessage
         * @private
         */

        /**
         * @property {String} waitForUploadMessageColor
         * @private
         */

        /**
         * @property {String} waitForWebcamImage
         * @private
         */

        /**
         * @property {String} waitForWebcamVideo
         * @private
         */

        /**
         * Whether to display the user's webcam
         *
         * @property {Boolean} showWebcam
         * @default false
         */
        showWebcam: {
            type: 'boolean',
            description: 'Whether to display the user\'s webcam',
            default: false
        },

        /**
         * Array of blocks for {{#crossLink "Exp-text-block"}}{{/crossLink}}, specifying text/images of instructions to display
         *
         * @property {Object[]} blocks
         *   @param {String} title Title of this section
         *   @param {String} text Paragraph text of this section
         *   @param {Object[]} listblocks Object specifying bulleted points for this section. Each object is of the form:
         *   {text: 'text of bullet point', image: {src: 'url', alt: 'alt-text'}}. Images are optional.
         *   @param {Object} mediaBlock Object specifying audio or video clip to include (optional). mediaBlock should be of form:
         *   {title: 'title text to show above audio', text: 'text to show below controls', warningText: 'Text to show in red if user tries to proceed but hasn't played; only used if mustPlay is true', sources: 'sources Array of {src: 'url', type: 'MIMEtype'} objects specifying audio sources', isVideo: 'boolean, whether video or audio', mustPlay: 'boolean, whether clip has to be played to proceed'}
         *
         */
        blocks: {
            type: 'array',
            items: {
                type: 'object',
                properties: {
                    title: {
                        type: 'string'
                    },
                    text: {
                        type: 'string'
                    },
                    listblocks: {
                        type: 'array',
                        items: {
                            type: 'object',
                            properties: {
                                text: {
                                    type: 'string'
                                },
                                image: {
                                    type: 'object',
                                    properties: {
                                        src: {
                                            type: 'string'
                                        },
                                        alt: {
                                            type: 'string'
                                        }
                                    }
                                }
                            }
                        }
                    },
                    mediaBlock: {
                        type: 'object',
                        default: {},
                        properties: {
                            title: {
                                type: 'string'
                            },
                            text: {
                                type: 'string'
                            },
                            warningText: {
                                type: 'string'
                            },
                            sources: {
                                type: 'array',
                                items: {
                                    type: 'object',
                                    properties: {
                                        src: {
                                            type: 'string'
                                        },
                                        type: {
                                            type: 'string'
                                        }
                                    }
                                }
                            },
                            isVideo: {
                                type: 'boolean',
                                default: false
                            },
                            mustPlay: {
                                type: 'boolean',
                                default: false
                            }
                        }
                    }
                }
            },
            default: []
        },
        /**
         * Array of objects specifying text/images of instructions to display under webcam view (if webcam is shown)
         *
         * @property {Object[]} blocks
         *   @param {String} title Title of this section
         *   @param {String} text Paragraph text of this section
         *   @param {Object[]} listblocks Object specifying bulleted points for this section. Each object is of the form:
         *   {text: 'text of bullet point', image: {src: 'url', alt: 'alt-text'}}. Images are optional.
         */
        webcamBlocks: {
            type: 'array',
            items: {
                type: 'object',
                properties: {
                    title: {
                        type: 'string'
                    },
                    text: {
                        type: 'string'
                    },
                    listblocks: {
                        type: 'array',
                        items: {
                            type: 'object',
                            properties: {
                                text: {
                                    type: 'string'
                                },
                                image: {
                                    type: 'object',
                                    properties: {
                                        src: {
                                            type: 'string'
                                        },
                                        alt: {
                                            type: 'string'
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            },
            default: []
        },
        /**
         * Whether to show a 'previous' button
         *
         * @property {Boolean} showPreviousButton
         * @default true
         */
        showPreviousButton: {
            type: 'boolean',
            default: true
        },
        /**
         * Text to display on the 'next frame' button
         *
         * @property {String} nextButtonText
         * @default 'Start the videos! \n (You\'ll have a moment to turn around.)'
         */
        nextButtonText: {
            type: 'string',
            default: 'Start the videos! \n (You\'ll have a moment to turn around.)'
        }
    },
    meta: {
        data: {
            type: 'object',
            properties: {
            }
        }
    },

    showWarning: false,

    actions: {
        mediaPlayed(e) {
            $(e.srcElement).attr('completed', true);
            $(e.srcElement).parent().attr('showWarning', false);
        },
        checkAudioThenNext() {
            if (this.shouldPreventNext()) {
                this.set('showWarning', true);
            } else {
                this.send('next');
            }
        }
    },

    shouldPreventNext() {
        var done = true;
        var blocks = this.get('blocks');
        for (var iBlock = 0; iBlock < blocks.length; iBlock++) { // for each block
            if (blocks[iBlock].hasOwnProperty('mediaBlock')) {   // if it has a mediaBlock
                // find the appropriate element
                var $elem = $('#media-' + iBlock + ' .player-media');
                if (blocks[iBlock].mediaBlock.hasOwnProperty('mustPlay') && blocks[iBlock].mediaBlock.mustPlay) { // if the mediaBlock must be played
                    // if it's not completed
                    if ($elem.attr('completed') != 'true') {
                        done = false;
                        $elem.parent().attr('showWarning', true);
                    }
                } else { // does not have to be played
                    $elem.parent().attr('showWarning', false); // Set this explicitly
                    // so the warning isn't visible, although :not([showWarning])
                    // selector should handle in almost all browsers
                }
            }
        }
        return !done;
    }
});