diff --git a/client/js/_author/components/assessments/question_types/image_sequence/_image_sequence.jsx b/client/js/_author/components/assessments/question_types/image_sequence/_image_sequence.jsx
index e90f56a7d..44459144e 100644
--- a/client/js/_author/components/assessments/question_types/image_sequence/_image_sequence.jsx
+++ b/client/js/_author/components/assessments/question_types/image_sequence/_image_sequence.jsx
@@ -30,9 +30,20 @@ class ImageSequence extends React.Component {
super(props);
this.state = {
choiceId: null,
+ hasChanged: false
};
}
+ onUpdateChoice = (itemId, choiceId, newChoice, fileIds) => {
+ this.setState({ hasChanged: true });
+ this.props.updateChoice(itemId, choiceId, newChoice, fileIds);
+ }
+
+ onSave = () => {
+ this.setState({ hasChanged: false });
+ this.props.save();
+ }
+
getFeedback() {
const { question } = this.props.item;
const strings = this.props.localizeStrings('imageSequence');
@@ -63,6 +74,21 @@ class ImageSequence extends React.Component {
}
render() {
+ let saveOptions = (
+
+ );
+
+ if (this.state.hasChanged) {
+ saveOptions = (
+
+ );
+ }
+
return (
-
+ {saveOptions}
{ this.getFeedback() }
diff --git a/client/js/_author/components/assessments/question_types/image_sequence/_image_sequence.spec.jsx b/client/js/_author/components/assessments/question_types/image_sequence/_image_sequence.spec.jsx
index c850050f8..640fdb830 100644
--- a/client/js/_author/components/assessments/question_types/image_sequence/_image_sequence.spec.jsx
+++ b/client/js/_author/components/assessments/question_types/image_sequence/_image_sequence.spec.jsx
@@ -50,6 +50,7 @@ describe('image sequence component', () => {
it('renders the component', () => {
expect(result.find('.au-c-question__feedback').length).toBe(2);
+ expect(result.state().hasChanged).toEqual(false);
});
it('renders two Feedback components', () => {
@@ -66,4 +67,16 @@ describe('image sequence component', () => {
feedback.at(0).nodes[0].props.updateItem();
expect(calledFunc).toBeTruthy();
});
+
+ it('changes state when call onUpdateChoice', () => {
+ expect(result.state().hasChanged).toEqual(false);
+ result.instance().onUpdateChoice();
+ expect(result.state().hasChanged).toEqual(true);
+ });
+
+ it('sets disabled flag correctly on the Save button', () => {
+ expect(result.find({ disabled: true }).length).toEqual(1);
+ result.setState({ hasChanged: true });
+ expect(result.find({ disabled: true }).length).toEqual(0);
+ });
});
diff --git a/client/js/_author/components/assessments/question_types/movable_word_sentence/movable_word_sentence.jsx b/client/js/_author/components/assessments/question_types/movable_word_sentence/movable_word_sentence.jsx
index 7c946ecbd..6dca840eb 100644
--- a/client/js/_author/components/assessments/question_types/movable_word_sentence/movable_word_sentence.jsx
+++ b/client/js/_author/components/assessments/question_types/movable_word_sentence/movable_word_sentence.jsx
@@ -28,10 +28,42 @@ class MovableWordSentence extends React.Component {
duplicateAnswers: React.PropTypes.arrayOf(React.PropTypes.string),
};
+ constructor(props) {
+ super(props);
+ this.state = {
+ hasChanged: false
+ };
+ }
+
+ onUpdateChoice = (itemId, choiceId, newChoice, fileIds) => {
+ this.setState({ hasChanged: true });
+ this.props.updateChoice(itemId, choiceId, newChoice, fileIds);
+ }
+
+ onSave = () => {
+ this.setState({ hasChanged: false });
+ this.props.save();
+ }
+
render() {
const { question, id } = this.props.item;
const strings = this.props.localizeStrings('movableWordSentence');
+ let saveOptions = (
+
+ );
+
+ if (this.state.hasChanged) {
+ saveOptions = (
+
+ );
+ }
+
return (
this.props.updateChoice(id, choice.id, newChoice, fileIds)
+ (newChoice, fileIds) => this.onUpdateChoice(id, choice.id, newChoice, fileIds)
}
isActive={this.props.isActive && choice.id === this.props.activeChoice}
deleteChoice={() => this.props.deleteChoice(choice)}
@@ -58,7 +90,7 @@ class MovableWordSentence extends React.Component {
this.props.createChoice()}
/>
-
+ {saveOptions}
{
it('renders the movable word sentence component', () => {
expect(result.find('.au-c-movable__answers'));
+ expect(result.state().hasChanged).toEqual(false);
});
it('renders Option', () => {
@@ -109,4 +110,16 @@ describe('movable word sentece component', () => {
result.find('.au-c-movable__answers').simulate('blur', { target: { value: 'Preposition' } });
expect(calledFunc).toBeTruthy();
});
+
+ it('changes state when call onUpdateChoice', () => {
+ expect(result.state().hasChanged).toEqual(false);
+ result.instance().onUpdateChoice();
+ expect(result.state().hasChanged).toEqual(true);
+ });
+
+ it('sets disabled flag correctly on the Save button', () => {
+ expect(result.find({ disabled: true }).length).toEqual(1);
+ result.setState({ hasChanged: true });
+ expect(result.find({ disabled: true }).length).toEqual(0);
+ });
});
diff --git a/client/js/_author/components/assessments/question_types/question_common/save_option_button.jsx b/client/js/_author/components/assessments/question_types/question_common/save_option_button.jsx
index 20d8d35b0..9ab86b695 100644
--- a/client/js/_author/components/assessments/question_types/question_common/save_option_button.jsx
+++ b/client/js/_author/components/assessments/question_types/question_common/save_option_button.jsx
@@ -3,10 +3,16 @@ import localize from '../../../../locales/localize';
function saveOption(props) {
const strings = props.localizeStrings('saveOption');
+ let classes = 'au-c-btn au-c-btn--sm au-c-btn--maroon au-u-ml-md';
+
+ if (props.disabled) {
+ classes += ' is-inactive';
+ }
return (
@@ -16,6 +22,7 @@ function saveOption(props) {
saveOption.propTypes = {
save: React.PropTypes.func.isRequired,
localizeStrings: React.PropTypes.func.isRequired,
+ disabled: React.PropTypes.bool
};
export default localize(saveOption);
diff --git a/client/js/_author/components/assessments/question_types/question_common/save_option_button.spec.jsx b/client/js/_author/components/assessments/question_types/question_common/save_option_button.spec.jsx
index cb158f4b1..64bf0806b 100644
--- a/client/js/_author/components/assessments/question_types/question_common/save_option_button.spec.jsx
+++ b/client/js/_author/components/assessments/question_types/question_common/save_option_button.spec.jsx
@@ -25,4 +25,11 @@ describe('save option button component', () => {
button.simulate('click');
expect(calledFunction).toBeTruthy();
});
+
+ it('has inactive class if disabled', () => {
+ expect(result.find('.is-inactive').length).toEqual(0);
+ props.disabled = true;
+ result = shallow();
+ expect(result.find('.is-inactive').length).toEqual(1);
+ });
});