Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 13 additions & 45 deletions components/corespring/multiple-choice/src/client/render.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ function MultipleChoiceDirective(
scope.isVertical = isVertical;
scope.letter = letter;
scope.onClickChoice = onClickChoice;
scope.shuffle = shuffle;

scope.containerBridge = {
answerChangedHandler: answerChangedHandler,
Expand All @@ -64,6 +63,7 @@ function MultipleChoiceDirective(
//------------------------------------------------

function setDataAndSession(dataAndSession) {
console.log("setDataAndSession", dataAndSession);
scope.question = dataAndSession.data.model || {};
scope.question.config = getConfigWithDefaults(scope.question.config);
scope.session = dataAndSession.session || {};
Expand Down Expand Up @@ -249,23 +249,7 @@ function MultipleChoiceDirective(
scope.answer.choice = "";
}

function shuffle(choices) {
var allChoices = _.cloneDeep(choices);
var shuffledChoices = _(allChoices).filter(choiceShouldBeShuffled).shuffle().value();
return _.map(allChoices, function(choice) {
if (choiceShouldBeShuffled(choice)) {
return shuffledChoices.pop();
} else {
return choice;
}
});
}

function choiceShouldBeShuffled(choice) {
return _.isUndefined(choice.shuffle) || choice.shuffle === true;
}

function restoreChoiceOrder(choices, order) {
function applyOrder(choices, order) {
var ordered = _(order).map(function(v) {
return _.find(choices, function(c) {
return c.value === v;
Expand All @@ -278,26 +262,13 @@ function MultipleChoiceDirective(
return _.union(ordered, missing);
}

function shuffleChoices(choices) {
return scope.shuffle(choices);
}

function stashOrder(choices) {
return _.map(choices, function(c) {
return c.value;
});
}

//TODO create new shuffling instead of deleting -> call to server?
function resetShuffledOrder() {
if (scope.session && scope.session.stash) {
delete scope.session.stash.shuffledOrder;
}
}

function isGatherMode() {
return scope.playerMode === 'gather' || !scope.playerMode;
}

function updateUi() {
if (!scope.question || !scope.session) {
return;
Expand All @@ -310,14 +281,11 @@ function MultipleChoiceDirective(
var clonedChoices = _.cloneDeep(model.choices);
var resultingChoices = clonedChoices;

if (scope.playerMode !== 'instructor') {
if (model.config.shuffle) {
if (stash.shuffledOrder) {
resultingChoices = restoreChoiceOrder(clonedChoices, stash.shuffledOrder);
} else {
resultingChoices = shuffleChoices(clonedChoices);
stash.shuffledOrder = stashOrder(resultingChoices);
scope.$emit('saveStash', attrs.id, stash);
if( model.config.shuffle){
//the shuffledOrder is created by the server
if (stash.shuffledOrder) {
if(scope.playerMode !== 'instructor') {
resultingChoices = applyOrder(clonedChoices, stash.shuffledOrder);
}
}
}
Expand All @@ -331,12 +299,12 @@ function MultipleChoiceDirective(
}

function letter(idx) {
var type = scope.question ? scope.question.config.choiceLabels : "letters";
var type = scope.question ? scope.question.config.choiceLabels : 'letters';
switch (type) {
case "none":
return "";
case "numbers":
return (idx + 1) + "";
case 'none':
return '';
case 'numbers':
return (idx + 1) + '';
}

// default to letters: A...Z
Expand Down
61 changes: 54 additions & 7 deletions components/corespring/multiple-choice/src/server/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,63 @@ exports.isCorrect = isCorrect;
exports.isPartiallyCorrect = isPartiallyCorrect;
exports.keys = keys;
exports.preprocess = preprocess;
exports.prepareStash = prepareStash;

//-------------------------------------------------------------

/**
* Called by the backend just before the session is rendered.
* The changes made here are temporary
*/
function preprocess(json) {
if (_.isUndefined(json.model.config.choiceType)) {
json.model.config.choiceType = (json.correctResponse.value.length === 1) ? "radio" : "checkbox";
}
return json;
}

/**
* Called by the backend when the session is created
* The object returned is saved to session.stash
* When null is returned, nothing is saved
*/
function prepareStash(data, session) {
if (!data.model.config.shuffle) {
return null;
}
if (session.stash && session.stash.shuffledOrder && session.stash.shuffledOrder.length === data.model.choices.length) {
return null;
}
var choiceIds = getChoiceIds(shuffle(data.model.choices));
return {
shuffledOrder: choiceIds
};

//--------------------------------------

function shuffle(choices) {
var allChoices = _.cloneDeep(choices);
var shuffledChoices = _(allChoices).filter(choiceShouldBeShuffled).shuffle().value();
return _.map(allChoices, function(choice) {
if (choiceShouldBeShuffled(choice)) {
return shuffledChoices.pop();
} else {
return choice;
}
});
}

function choiceShouldBeShuffled(choice) {
return choice.shuffle === true || _.isUndefined(choice.shuffle);
}

function getChoiceIds(choices) {
return _.map(choices, function(c) {
return c.value;
});
}
}

/*
Create a response to the answer based on the question, the answer and the respond settings
*/
Expand Down Expand Up @@ -155,13 +209,6 @@ function correctResponseFeedback(fbArray, q, userGotItRight, answer) {
}
}

function preprocess(json) {
if (_.isUndefined(json.model.config.choiceType)) {
json.model.config.choiceType = (json.correctResponse.value.length === 1) ? "radio" : "checkbox";
}
return json;
}

function isPartiallyCorrect(answers, correctAnswers) {
var countAnsweredCorrectly = _.reduce(answers, function(sum, answer) {
var increment = _.contains(correctAnswers, answer) ? 1 : 0;
Expand Down
75 changes: 0 additions & 75 deletions components/corespring/multiple-choice/test/client/render-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,83 +96,8 @@ describe('corespring:multiple-choice-render', function() {
expect(testModel.data.model.config.shuffle).toBe(true);
});

it('shuffles when shuffle is true', function() {
spyOn(scope, 'shuffle');
container.elements['1'].setDataAndSession(testModel);
expect(scope.shuffle).toHaveBeenCalled();
});

it('shuffles every time when reset is called', function() {
container.elements['1'].setDataAndSession(testModel);
spyOn(scope, 'shuffle');
container.elements['1'].reset();
container.elements['1'].reset();
container.elements['1'].reset();
expect(scope.shuffle).toHaveBeenCalledTimes(3);
});

it('does not shuffle when shuffle is false', function() {
spyOn(scope, 'shuffle');
testModel.data.model.config.shuffle = false;
container.elements['1'].setDataAndSession(testModel);
expect(scope.shuffle).not.toHaveBeenCalled();
});

it('does shuffle when mode is gather', function() {
spyOn(scope, 'shuffle');
container.elements['1'].setMode('gather');
container.elements['1'].setDataAndSession(testModel);
expect(scope.shuffle).toHaveBeenCalled();
});

it('does shuffle when mode is view', function() {
spyOn(scope, 'shuffle');
container.elements['1'].setMode('view');
container.elements['1'].setDataAndSession(testModel);
expect(scope.shuffle).toHaveBeenCalled();
});

it('does shuffle when mode is evaluate', function() {
spyOn(scope, 'shuffle');
container.elements['1'].setMode('evaluate');
container.elements['1'].setDataAndSession(testModel);
expect(scope.shuffle).toHaveBeenCalled();
});

it('does not shuffle when mode is instructor', function() {
spyOn(scope, 'shuffle');
container.elements['1'].setMode('instructor');
container.elements['1'].setDataAndSession(testModel);
expect(scope.shuffle).not.toHaveBeenCalled();
});

describe('stashing', function() {

it('stashes shuffledOrder', function() {
var saveStashCallElementId;
var saveStashCallData;
scope.$on('saveStash', function(evt, id, data) {
saveStashCallElementId = id;
saveStashCallData = data;
});
container.elements['1'].setDataAndSession(testModel);
expect(saveStashCallElementId).toEqual('1');
expect(saveStashCallData.shuffledOrder).toContain('1');
expect(saveStashCallData.shuffledOrder).toContain('2');
expect(saveStashCallData.shuffledOrder).toContain('3');
});

it('does not shuffle when session contains shuffledOrder', function() {
spyOn(scope, 'shuffle');
testModel.session = {
stash: {
shuffledOrder: ["1", "2", "3"]
}
};
container.elements['1'].setDataAndSession(testModel);
expect(scope.shuffle).not.toHaveBeenCalled();
});

it('does apply shuffledOrder in modes gather, view and evaluate', function() {

function assertShuffledOrder(mode) {
Expand Down