← All changes
|
assets/src/apps/js/frontend/quiz/components/questions/question.js
+292
-245
4.3.8
→
4.4.10
View file →
| @@ -1,245 +1,292 @@ | ||
| 1 | -import { Component, Fragment } from '@wordpress/element'; | |
| 2 | -import { withSelect, withDispatch } from '@wordpress/data'; | |
| 3 | -import { compose } from '@wordpress/compose'; | |
| 4 | -import { __, sprintf } from '@wordpress/i18n'; | |
| 5 | -import Buttons from './buttons'; | |
| 6 | -import { MaybeShowButton } from '../buttons'; | |
| 7 | -import { default as ButtonCheck } from '../buttons/button-check'; | |
| 8 | -import { default as ButtonHint } from '../buttons/button-hint'; | |
| 9 | - | |
| 10 | -const $ = window.jQuery; | |
| 11 | -const { uniqueId, isArray, isNumber, bind } = lodash; | |
| 12 | - | |
| 13 | -class Question extends Component { | |
| 14 | - constructor() { | |
| 15 | - super( ...arguments ); | |
| 16 | - | |
| 17 | - this.state = { | |
| 18 | - time: null, | |
| 19 | - showHint: false, | |
| 20 | - }; | |
| 21 | - | |
| 22 | - this.$wrap = null; | |
| 23 | - } | |
| 24 | - | |
| 25 | - componentDidMount( a ) { | |
| 26 | - const { | |
| 27 | - question, | |
| 28 | - isCurrent, | |
| 29 | - markQuestionRendered, | |
| 30 | - } = this.props; | |
| 31 | - | |
| 32 | - if ( isCurrent ) { | |
| 33 | - markQuestionRendered( question.id ); | |
| 34 | - } | |
| 35 | - | |
| 36 | - if ( ! this.state.time ) { | |
| 37 | - this.setState( { | |
| 38 | - time: new Date(), | |
| 39 | - } ); | |
| 40 | - } | |
| 41 | - | |
| 42 | - LP.Hook.doAction( 'lp-question-compatible-builder' ); | |
| 43 | - | |
| 44 | - if ( typeof MathJax !== 'undefined' && typeof MathJax.Hub !== 'undefined' ) { | |
| 45 | - MathJax.Hub.Queue( [ 'Typeset', MathJax.Hub ] ); | |
| 46 | - } | |
| 47 | - | |
| 48 | - return a; | |
| 49 | - } | |
| 50 | - | |
| 51 | - setRef = ( el ) => { | |
| 52 | - this.$wrap = $( el ); | |
| 53 | - }; | |
| 54 | - | |
| 55 | - parseOptions = ( options ) => { | |
| 56 | - if ( options ) { | |
| 57 | - options = ! isArray( options ) ? JSON.parse( CryptoJS.AES.decrypt( options.data, options.key, { format: CryptoJSAesJson } ).toString( CryptoJS.enc.Utf8 ) ) : options; | |
| 58 | - options = ! isArray( options ) ? JSON.parse( options ) : options; | |
| 59 | - } | |
| 60 | - | |
| 61 | - return options || []; | |
| 62 | - }; | |
| 63 | - | |
| 64 | - getWrapperClass = () => { | |
| 65 | - const { question, answered } = this.props; | |
| 66 | - | |
| 67 | - const classes = [ 'question', 'question-' + question.type ]; | |
| 68 | - const options = this.parseOptions( question.options ); | |
| 69 | - | |
| 70 | - if ( options.length && options[ 0 ].isTrue !== undefined ) { | |
| 71 | - classes.push( 'question-answered' ); | |
| 72 | - } | |
| 73 | - | |
| 74 | - return classes; | |
| 75 | - }; | |
| 76 | - | |
| 77 | - getEditLink = () => { | |
| 78 | - const { | |
| 79 | - question, | |
| 80 | - editPermalink, | |
| 81 | - } = this.props; | |
| 82 | - | |
| 83 | - return editPermalink ? editPermalink.replace( /post=(.*[0-9])/, `post=${ question.id }` ) : ''; | |
| 84 | - }; | |
| 85 | - | |
| 86 | - editPermalink = ( editPermalink ) => { | |
| 87 | - return sprintf( '<a href="%s">%s</a>', editPermalink, __( 'Edit', 'learnpress' ) ); | |
| 88 | - }; | |
| 89 | - | |
| 90 | - render() { | |
| 91 | - const { | |
| 92 | - question, | |
| 93 | - isShow, | |
| 94 | - isShowIndex, | |
| 95 | - isShowHint, | |
| 96 | - status, | |
| 97 | - } = this.props; | |
| 98 | - | |
| 99 | - const QuestionTypes = LP.questionTypes.default; | |
| 100 | - const editPermalink = this.getEditLink(); | |
| 101 | - | |
| 102 | - if ( editPermalink ) { | |
| 103 | - jQuery( '#wp-admin-bar-edit-lp_question' ).find( '.ab-item' ).attr( 'href', editPermalink ); | |
| 104 | - } | |
| 105 | - | |
| 106 | - const titleParts = { | |
| 107 | - index: () => { | |
| 108 | - return ( isShowIndex ? <span className="question-index">{ isShowIndex }.</span> : '' ); | |
| 109 | - }, | |
| 110 | - | |
| 111 | - title: () => { | |
| 112 | - return ( <span dangerouslySetInnerHTML={ { __html: question.title } } /> ); | |
| 113 | - }, | |
| 114 | - | |
| 115 | - hint: () => { | |
| 116 | - return <ButtonHint question={ question }></ButtonHint>; | |
| 117 | - }, | |
| 118 | - | |
| 119 | - 'edit-permalink': () => { | |
| 120 | - return ( | |
| 121 | - editPermalink && ( | |
| 122 | - <span | |
| 123 | - dangerouslySetInnerHTML={ { __html: this.editPermalink( editPermalink ) } } | |
| 124 | - className="edit-link"> | |
| 125 | - </span> | |
| 126 | - ) | |
| 127 | - ); | |
| 128 | - }, | |
| 129 | - }; | |
| 130 | - | |
| 131 | - const blocks = { | |
| 132 | - title: () => { | |
| 133 | - return ( | |
| 134 | - <h4 className="question-title"> | |
| 135 | - { LP.config.questionTitleParts().map( ( name ) => { | |
| 136 | - return ( | |
| 137 | - <Fragment key={ `title-part-${ name }` }> | |
| 138 | - { titleParts[ name ] && titleParts[ name ]() } | |
| 139 | - </Fragment> | |
| 140 | - ); | |
| 141 | - } ) } | |
| 142 | - </h4> | |
| 143 | - ); | |
| 144 | - }, | |
| 145 | - | |
| 146 | - content: () => { | |
| 147 | - return ( | |
| 148 | - <div className="question-content" dangerouslySetInnerHTML={ { __html: question.content } } /> | |
| 149 | - ); | |
| 150 | - }, | |
| 151 | - | |
| 152 | - 'answer-options': () => { | |
| 153 | - return ( | |
| 154 | - this.$wrap && <QuestionTypes { ...{ ...this.props, $wrap: this.$wrap } } /> | |
| 155 | - ); | |
| 156 | - }, | |
| 157 | - | |
| 158 | - explanation: () => { | |
| 159 | - return ( | |
| 160 | - question.explanation && ( | |
| 161 | - <> | |
| 162 | - <div className="question-explanation-content"> | |
| 163 | - <strong className="explanation-title">{ __( 'Explanation', 'learnpress' ) }:</strong> | |
| 164 | - <div dangerouslySetInnerHTML={ { __html: question.explanation } }> | |
| 165 | - </div> | |
| 166 | - </div> | |
| 167 | - </> | |
| 168 | - ) | |
| 169 | - ); | |
| 170 | - }, | |
| 171 | - | |
| 172 | - hint: () => { | |
| 173 | - return ( | |
| 174 | - question.hint && ! question.explanation && question.showHint && ( | |
| 175 | - <> | |
| 176 | - <div className="question-hint-content"> | |
| 177 | - <strong className="hint-title">{ __( 'Hint', 'learnpress' ) }:</strong> | |
| 178 | - <div dangerouslySetInnerHTML={ { __html: question.hint } } /> | |
| 179 | - </div> | |
| 180 | - </> | |
| 181 | - ) | |
| 182 | - ); | |
| 183 | - }, | |
| 184 | - | |
| 185 | - buttons: () => { | |
| 186 | - return ( | |
| 187 | - ( 'started' === status ) && <Buttons question={ question } /> | |
| 188 | - ); | |
| 189 | - }, | |
| 190 | - }; | |
| 191 | - | |
| 192 | - const configBlocks = LP.config.questionBlocks(); | |
| 193 | - | |
| 194 | - return ( | |
| 195 | - <> | |
| 196 | - <div className={ this.getWrapperClass().join( ' ' ) } | |
| 197 | - style={ { display: isShow ? '' : 'none' } } | |
| 198 | - data-id={ question.id } | |
| 199 | - ref={ this.setRef }> | |
| 200 | - | |
| 201 | - { configBlocks.map( ( name ) => { | |
| 202 | - return ( | |
| 203 | - <Fragment key={ `block-${ name }` }> | |
| 204 | - { blocks[ name ] ? blocks[ name ]() : '' } | |
| 205 | - </Fragment> | |
| 206 | - ); | |
| 207 | - } ) } | |
| 208 | - </div> | |
| 209 | - </> | |
| 210 | - ); | |
| 211 | - } | |
| 212 | -} | |
| 213 | - | |
| 214 | -export default compose( [ | |
| 215 | - withSelect( ( select, { question: { id } } ) => { | |
| 216 | - const { | |
| 217 | - getData, | |
| 218 | - getQuestionAnswered, | |
| 219 | - getQuestionMark, | |
| 220 | - } = select( 'learnpress/quiz' ); | |
| 221 | - | |
| 222 | - return { | |
| 223 | - status: getData( 'status' ), | |
| 224 | - questions: getData( 'question' ), | |
| 225 | - answered: getQuestionAnswered( id ), | |
| 226 | - questionsRendered: getData( 'questionsRendered' ), | |
| 227 | - editPermalink: getData( 'editPermalink' ), | |
| 228 | - numPages: getData( 'numPages' ), | |
| 229 | - mark: getQuestionMark( id ) || '', | |
| 230 | - }; | |
| 231 | - } ), | |
| 232 | - withDispatch( ( dispatch ) => { | |
| 233 | - const { | |
| 234 | - updateUserQuestionAnswers, | |
| 235 | - updateUserQuestionFibAnswers, | |
| 236 | - markQuestionRendered, | |
| 237 | - } = dispatch( 'learnpress/quiz' ); | |
| 238 | - | |
| 239 | - return { | |
| 240 | - markQuestionRendered, | |
| 241 | - updateUserQuestionAnswers, | |
| 242 | - updateUserQuestionFibAnswers, | |
| 243 | - }; | |
| 244 | - } ), | |
| 245 | -] )( Question ); | |
| 1 | +import { Component, Fragment } from '@wordpress/element'; | |
| 2 | +import { withSelect, withDispatch } from '@wordpress/data'; | |
| 3 | +import { compose } from '@wordpress/compose'; | |
| 4 | +import { __, sprintf } from '@wordpress/i18n'; | |
| 5 | +import Buttons from './buttons'; | |
| 6 | +import { MaybeShowButton } from '../buttons'; | |
| 7 | +import { default as ButtonCheck } from '../buttons/button-check'; | |
| 8 | +import { default as ButtonHint } from '../buttons/button-hint'; | |
| 9 | + | |
| 10 | +const $ = window.jQuery; | |
| 11 | +const { uniqueId, isArray, isNumber, bind } = lodash; | |
| 12 | + | |
| 13 | +class Question extends Component { | |
| 14 | + constructor() { | |
| 15 | + super( ...arguments ); | |
| 16 | + | |
| 17 | + this.state = { | |
| 18 | + time: null, | |
| 19 | + showHint: false, | |
| 20 | + }; | |
| 21 | + | |
| 22 | + this.$wrap = null; | |
| 23 | + } | |
| 24 | + | |
| 25 | + componentDidMount( a ) { | |
| 26 | + const { question, isCurrent, markQuestionRendered } = this.props; | |
| 27 | + | |
| 28 | + if ( isCurrent ) { | |
| 29 | + markQuestionRendered( question.id ); | |
| 30 | + } | |
| 31 | + | |
| 32 | + if ( ! this.state.time ) { | |
| 33 | + this.setState( { | |
| 34 | + time: new Date(), | |
| 35 | + } ); | |
| 36 | + } | |
| 37 | + | |
| 38 | + LP.Hook.doAction( 'lp-question-compatible-builder' ); | |
| 39 | + | |
| 40 | + if ( | |
| 41 | + typeof MathJax !== 'undefined' && | |
| 42 | + typeof MathJax.Hub !== 'undefined' | |
| 43 | + ) { | |
| 44 | + MathJax.Hub.Queue( [ 'Typeset', MathJax.Hub ] ); | |
| 45 | + } | |
| 46 | + | |
| 47 | + return a; | |
| 48 | + } | |
| 49 | + | |
| 50 | + setRef = ( el ) => { | |
| 51 | + this.$wrap = $( el ); | |
| 52 | + }; | |
| 53 | + | |
| 54 | + parseOptions = ( options ) => { | |
| 55 | + if ( options ) { | |
| 56 | + options = ! isArray( options ) | |
| 57 | + ? JSON.parse( | |
| 58 | + CryptoJS.AES.decrypt( options.data, options.key, { | |
| 59 | + format: CryptoJSAesJson, | |
| 60 | + } ).toString( CryptoJS.enc.Utf8 ) | |
| 61 | + ) | |
| 62 | + : options; | |
| 63 | + options = ! isArray( options ) ? JSON.parse( options ) : options; | |
| 64 | + } | |
| 65 | + | |
| 66 | + return options || []; | |
| 67 | + }; | |
| 68 | + | |
| 69 | + getWrapperClass = () => { | |
| 70 | + const { question, answered } = this.props; | |
| 71 | + | |
| 72 | + const classes = [ 'question', 'question-' + question.type ]; | |
| 73 | + const options = this.parseOptions( question.options ); | |
| 74 | + | |
| 75 | + if ( options.length && options[ 0 ].isTrue !== undefined ) { | |
| 76 | + classes.push( 'question-answered' ); | |
| 77 | + } | |
| 78 | + | |
| 79 | + return classes; | |
| 80 | + }; | |
| 81 | + | |
| 82 | + getEditLink = () => { | |
| 83 | + const { question, editPermalink } = this.props; | |
| 84 | + | |
| 85 | + return editPermalink | |
| 86 | + ? editPermalink.replace( /post=(.*[0-9])/, `post=${ question.id }` ) | |
| 87 | + : ''; | |
| 88 | + }; | |
| 89 | + | |
| 90 | + editPermalink = ( editPermalink ) => { | |
| 91 | + return sprintf( | |
| 92 | + '<a href="%s">%s</a>', | |
| 93 | + editPermalink, | |
| 94 | + __( 'Edit', 'learnpress' ) | |
| 95 | + ); | |
| 96 | + }; | |
| 97 | + | |
| 98 | + render() { | |
| 99 | + const { question, isShow, isShowIndex, isShowHint, status, results } = | |
| 100 | + this.props; | |
| 101 | + | |
| 102 | + if ( | |
| 103 | + results && | |
| 104 | + results.questions && | |
| 105 | + results.questions[ question.id ] | |
| 106 | + ) { | |
| 107 | + if ( | |
| 108 | + typeof results.questions[ question.id ].correct !== 'undefined' | |
| 109 | + ) { | |
| 110 | + question.correct = results.questions[ question.id ].correct; | |
| 111 | + } | |
| 112 | + } | |
| 113 | + | |
| 114 | + const QuestionTypes = LP.questionTypes.default; | |
| 115 | + const editPermalink = this.getEditLink(); | |
| 116 | + | |
| 117 | + if ( editPermalink ) { | |
| 118 | + jQuery( '#wp-admin-bar-edit-lp_question' ) | |
| 119 | + .find( '.ab-item' ) | |
| 120 | + .attr( 'href', editPermalink ); | |
| 121 | + } | |
| 122 | + | |
| 123 | + const titleParts = { | |
| 124 | + index: () => { | |
| 125 | + return isShowIndex ? ( | |
| 126 | + <span className="question-index">{ isShowIndex }.</span> | |
| 127 | + ) : ( | |
| 128 | + '' | |
| 129 | + ); | |
| 130 | + }, | |
| 131 | + | |
| 132 | + title: () => { | |
| 133 | + return ( | |
| 134 | + <span | |
| 135 | + dangerouslySetInnerHTML={ { __html: question.title } } | |
| 136 | + /> | |
| 137 | + ); | |
| 138 | + }, | |
| 139 | + | |
| 140 | + hint: () => { | |
| 141 | + return <ButtonHint question={ question }></ButtonHint>; | |
| 142 | + }, | |
| 143 | + | |
| 144 | + 'edit-permalink': () => { | |
| 145 | + return ( | |
| 146 | + editPermalink && ( | |
| 147 | + <span | |
| 148 | + dangerouslySetInnerHTML={ { | |
| 149 | + __html: this.editPermalink( editPermalink ), | |
| 150 | + } } | |
| 151 | + className="edit-link" | |
| 152 | + ></span> | |
| 153 | + ) | |
| 154 | + ); | |
| 155 | + }, | |
| 156 | + }; | |
| 157 | + | |
| 158 | + const blocks = { | |
| 159 | + title: () => { | |
| 160 | + return ( | |
| 161 | + <h4 className="question-title"> | |
| 162 | + { LP.config.questionTitleParts().map( ( name ) => { | |
| 163 | + return ( | |
| 164 | + <Fragment key={ `title-part-${ name }` }> | |
| 165 | + { titleParts[ name ] && | |
| 166 | + titleParts[ name ]() } | |
| 167 | + </Fragment> | |
| 168 | + ); | |
| 169 | + } ) } | |
| 170 | + </h4> | |
| 171 | + ); | |
| 172 | + }, | |
| 173 | + | |
| 174 | + content: () => { | |
| 175 | + return ( | |
| 176 | + <div | |
| 177 | + className="question-content" | |
| 178 | + dangerouslySetInnerHTML={ { __html: question.content } } | |
| 179 | + /> | |
| 180 | + ); | |
| 181 | + }, | |
| 182 | + | |
| 183 | + 'answer-options': () => { | |
| 184 | + return ( | |
| 185 | + this.$wrap && ( | |
| 186 | + <QuestionTypes | |
| 187 | + { ...{ ...this.props, $wrap: this.$wrap } } | |
| 188 | + /> | |
| 189 | + ) | |
| 190 | + ); | |
| 191 | + }, | |
| 192 | + | |
| 193 | + explanation: () => { | |
| 194 | + return ( | |
| 195 | + question.explanation && ( | |
| 196 | + <> | |
| 197 | + <div className="question-explanation-content"> | |
| 198 | + <strong className="explanation-title"> | |
| 199 | + { __( 'Explanation', 'learnpress' ) }: | |
| 200 | + </strong> | |
| 201 | + <div | |
| 202 | + dangerouslySetInnerHTML={ { | |
| 203 | + __html: question.explanation, | |
| 204 | + } } | |
| 205 | + ></div> | |
| 206 | + </div> | |
| 207 | + </> | |
| 208 | + ) | |
| 209 | + ); | |
| 210 | + }, | |
| 211 | + | |
| 212 | + hint: () => { | |
| 213 | + return ( | |
| 214 | + question.hint && | |
| 215 | + ! question.explanation && | |
| 216 | + question.showHint && ( | |
| 217 | + <> | |
| 218 | + <div className="question-hint-content"> | |
| 219 | + <strong className="hint-title"> | |
| 220 | + { __( 'Hint', 'learnpress' ) }: | |
| 221 | + </strong> | |
| 222 | + <div | |
| 223 | + dangerouslySetInnerHTML={ { | |
| 224 | + __html: question.hint, | |
| 225 | + } } | |
| 226 | + /> | |
| 227 | + </div> | |
| 228 | + </> | |
| 229 | + ) | |
| 230 | + ); | |
| 231 | + }, | |
| 232 | + | |
| 233 | + buttons: () => { | |
| 234 | + return ( | |
| 235 | + 'started' === status && <Buttons question={ question } /> | |
| 236 | + ); | |
| 237 | + }, | |
| 238 | + }; | |
| 239 | + | |
| 240 | + const configBlocks = LP.config.questionBlocks(); | |
| 241 | + | |
| 242 | + return ( | |
| 243 | + <> | |
| 244 | + <div | |
| 245 | + className={ this.getWrapperClass().join( ' ' ) } | |
| 246 | + style={ { display: isShow ? '' : 'none' } } | |
| 247 | + data-id={ question.id } | |
| 248 | + ref={ this.setRef } | |
| 249 | + > | |
| 250 | + { configBlocks.map( ( name ) => { | |
| 251 | + return ( | |
| 252 | + <Fragment key={ `block-${ name }` }> | |
| 253 | + { blocks[ name ] ? blocks[ name ]() : '' } | |
| 254 | + </Fragment> | |
| 255 | + ); | |
| 256 | + } ) } | |
| 257 | + </div> | |
| 258 | + </> | |
| 259 | + ); | |
| 260 | + } | |
| 261 | +} | |
| 262 | + | |
| 263 | +export default compose( [ | |
| 264 | + withSelect( ( select, { question: { id } } ) => { | |
| 265 | + const { getData, getQuestionAnswered, getQuestionMark } = | |
| 266 | + select( 'learnpress/quiz' ); | |
| 267 | + | |
| 268 | + return { | |
| 269 | + status: getData( 'status' ), | |
| 270 | + questions: getData( 'question' ), | |
| 271 | + answered: getQuestionAnswered( id ), | |
| 272 | + questionsRendered: getData( 'questionsRendered' ), | |
| 273 | + editPermalink: getData( 'editPermalink' ), | |
| 274 | + numPages: getData( 'numPages' ), | |
| 275 | + mark: getQuestionMark( id ) || '', | |
| 276 | + results: getData( 'results' ), | |
| 277 | + }; | |
| 278 | + } ), | |
| 279 | + withDispatch( ( dispatch ) => { | |
| 280 | + const { | |
| 281 | + updateUserQuestionAnswers, | |
| 282 | + updateUserQuestionFibAnswers, | |
| 283 | + markQuestionRendered, | |
| 284 | + } = dispatch( 'learnpress/quiz' ); | |
| 285 | + | |
| 286 | + return { | |
| 287 | + markQuestionRendered, | |
| 288 | + updateUserQuestionAnswers, | |
| 289 | + updateUserQuestionFibAnswers, | |
| 290 | + }; | |
| 291 | + } ), | |
| 292 | +] )( Question ); | |