Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

issue/2876 JSX version of gmcq #124

Merged
merged 11 commits into from
Aug 27, 2021
3 changes: 3 additions & 0 deletions js/GmcqModel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import McqModel from 'components/adapt-contrib-mcq/js/mcqModel';

export default class GmcqModel extends McqModel {}
13 changes: 13 additions & 0 deletions js/GmcqView.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import McqView from 'components/adapt-contrib-mcq/js/mcqView';

class GmcqView extends McqView {

onQuestionRendered() {
this.$('.js-item-label').imageready(() => this.setReadyStatus());
}

}

GmcqView.template = 'gmcq.jsx';

export default GmcqView;
112 changes: 6 additions & 106 deletions js/adapt-contrib-gmcq.js
Original file line number Diff line number Diff line change
@@ -1,108 +1,8 @@
define([
'core/js/adapt',
'components/adapt-contrib-mcq/js/adapt-contrib-mcq'
], function(Adapt, Mcq) {

var Gmcq = Mcq.view.extend({

setupQuestion: function() {
Mcq.view.prototype.setupQuestion.call(this);

this.listenTo(Adapt, {
'device:changed': this.resizeImage,
'device:resize': this.onDeviceResize
});

},

onQuestionRendered: function() {

this.resizeImage(Adapt.device.screenSize);
this.setUpColumns();

this.$('.js-item-label').imageready(this.setReadyStatus.bind(this));

},

onDeviceResize: function() {
this.setUpColumns();
},

resizeImage: function(width) {
var imageWidth = width === 'medium' ? 'small' : width;

this.$('.js-item-label').each(function(index) {
var $img = $(this).find('img');
var newSrc = $img.attr('data-' + imageWidth);
if (!newSrc) return;
$img.attr('src', newSrc);
});

},

setUpColumns: function() {
var columns = this.model.get('_columns');

if (!columns) return;

var isLarge = Adapt.device.screenSize === 'large';

this.$el.toggleClass('has-column-layout', isLarge);
this.$('.js-mcq-item').css('width', isLarge ? (100 / columns) + '%' : '');
},

updateMarking: function() {

var isInteractive = this.model.isInteractive();
var canShowMarking = this.model.get('_canShowMarking');
var ariaLabels = Adapt.course.get('_globals')._accessibility._ariaLabels;

this.model.getChildren().forEach(function(itemModel) {

var index = itemModel.get('_index');
var $itemInput = this.$('.js-item-input').filter('[data-adapt-index="' + index + '"]');
var $item = $itemInput.parents('.js-mcq-item');

if (isInteractive || !canShowMarking) {
// Remove item marking
$item.removeClass('is-correct is-incorrect');
$itemInput.attr('aria-label', [
Adapt.a11y.normalize(itemModel.get('text')),
'. ',
Adapt.a11y.normalize(itemModel.get('_graphic').alt)
].join(''));
return;
}

// Mark item
var shouldBeSelected = itemModel.get('_shouldBeSelected');
var isCorrect = Boolean(itemModel.get('_isCorrect'));
var isActive = Boolean(itemModel.get('_isActive'));

$item
.toggleClass('is-correct', isCorrect)
.toggleClass('is-incorrect', !isCorrect);

$itemInput.attr('aria-label', [
(shouldBeSelected ? ariaLabels.correct : ariaLabels.incorrect),
', ',
(isActive ? ariaLabels.selectedAnswer : ariaLabels.unselectedAnswer),
'. ',
$.a11y_normalize(itemModel.get('text')),
'. ',
$.a11y_normalize(itemModel.get('_graphic').alt)
].join(''));

}, this);
}

}, {
template: 'gmcq'
});

return Adapt.register('gmcq', {
view: Gmcq,
model: Mcq.model.extend({})
});
import Adapt from 'core/js/adapt';
import GmcqView from './GmcqView';
import GmcqModel from './GmcqModel';

export default Adapt.register('gmcq', {
model: GmcqModel,
view: GmcqView
});
57 changes: 0 additions & 57 deletions templates/gmcq.hbs

This file was deleted.

140 changes: 140 additions & 0 deletions templates/gmcq.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
import Adapt from 'core/js/adapt';
import React from 'react';
import { templates, classes, html, compile } from 'core/js/reactHelpers';

export default function Gmcq(props) {
const ariaLabels = Adapt.course.get('_globals')._accessibility._ariaLabels;

const {
_id,
_isEnabled,
_isInteractionComplete,
_isCorrect,
_isCorrectAnswerShown,
_canShowMarking,
_isRadio,
_columns,
displayTitle,
body,
instruction,
onKeyPress,
onItemSelect,
onItemFocus,
onItemBlur,
isInteractive
} = props;

const screenSize = Adapt.device.screenSize;
const shouldShowMarking = isInteractive() && _canShowMarking;

return (
<div className='component__inner gmcq__inner'>

<templates.header {...props} />

<div
className={classes([
'component__widget',
'gmcq__widget',
!_isEnabled && 'is-disabled',
_isInteractionComplete && 'is-complete is-submitted show-user-answer',
_isCorrect && 'is-correct',
_columns && screenSize === 'large' && 'has-column-layout'
])}
role={_isRadio ? 'radiogroup' : 'group'}
aria-labelledby={(displayTitle || body || instruction) && `${_id}-header`}
>

{props._items.map(({ text, _index, _isActive, _shouldBeSelected, _graphic }, index) =>

<div
className={classes([
`gmcq__item item-${index}`,
(shouldShowMarking && _shouldBeSelected) ? 'is-correct' : null,
(shouldShowMarking && !_shouldBeSelected) ? 'is-incorrect' : null
])}
style={(_columns && screenSize === 'large') ?
{ width: `${100 / _columns}%` } :
null}
key={_index}
>

<input
className='gmcq__item-input'
id={`${_id}-${index}-input`}
name={_isRadio ? `${_id}-item` : null}
type={_isRadio ? 'radio' : 'checkbox'}
disabled={!_isEnabled}
aria-label={!shouldShowMarking ?
`${Adapt.a11y.normalize(text)} ${_graphic?.alt || ''}` :
`${_shouldBeSelected ? ariaLabels.correct : ariaLabels.incorrect}, ${_isActive ? ariaLabels.selectedAnswer : ariaLabels.unselectedAnswer}. ${Adapt.a11y.normalize(text)} ${_graphic?.alt || ''}`}
data-adapt-index={_index}
onKeyPress={onKeyPress}
onChange={onItemSelect}
onFocus={onItemFocus}
onBlur={onItemBlur}
/>

<label
className={classes([
'gmcq__item-label',
'js-item-label',
!_isEnabled && 'is-disabled',
(_isCorrectAnswerShown ? _shouldBeSelected : _isActive) && 'is-selected'
])}
aria-hidden={true}
htmlFor={`${_id}-${index}-input`}
data-adapt-index={_index}
>

<templates.image {..._graphic}
classNamePrefixes={['gmcq__item']}
attributionClassNamePrefixes={['component', 'gmcq']}
/>

<div className='gmcq__item-option'>

<div className='gmcq__item-state'>
<div
className={classes([
'gmcq__item-icon',
'gmcq__item-answer-icon',
_isRadio ? 'is-radio' : 'is-checkbox'
])}
>

<div className='icon'></div>

</div>

<div className='gmcq__item-icon gmcq__item-correct-icon'>
<div className='icon'></div>
</div>

<div className='gmcq__item-icon gmcq__item-incorrect-icon'>
<div className='icon'></div>
</div>
</div>

{text &&
<div className='gmcq__item-text'>
<div className='gmcq__item-text-inner'>
{html(compile(text))}
</div>
</div>
}

</div>

</label>

</div>
)}

</div>

<div className='btn__container'></div>

</div>
);
}