diff --git a/www/addons/qtype/gapselect/handlers.js b/www/addons/qtype/gapselect/handlers.js
index bd45bbfb68d..2c6c550252d 100644
--- a/www/addons/qtype/gapselect/handlers.js
+++ b/www/addons/qtype/gapselect/handlers.js
@@ -28,10 +28,11 @@ angular.module('mm.addons.qtype_gapselect')
/**
* Check if a response is complete.
*
- * @param {Object} answers Question answers (without prefix).
- * @return {Mixed} True if complete, false if not complete, -1 if cannot determine.
+ * @param {Object} question Question.
+ * @param {Object} answers Question answers (without prefix).
+ * @return {Mixed} True if complete, false if not complete, -1 if cannot determine.
*/
- self.isCompleteResponse = function(answers) {
+ self.isCompleteResponse = function(question, answers) {
// We should always get a value for each select so we can assume we receive all the possible answers.
var isComplete = true;
angular.forEach(answers, function(value) {
@@ -55,10 +56,11 @@ angular.module('mm.addons.qtype_gapselect')
* Check if a student has provided enough of an answer for the question to be graded automatically,
* or whether it must be considered aborted.
*
- * @param {Object} answers Question answers (without prefix).
- * @return {Mixed} True if gradable, false if not gradable, -1 if cannot determine.
+ * @param {Object} question Question.
+ * @param {Object} answers Question answers (without prefix).
+ * @return {Mixed} True if gradable, false if not gradable, -1 if cannot determine.
*/
- self.isGradableResponse = function(answers) {
+ self.isGradableResponse = function(question, answers) {
var hasReponse = false;
angular.forEach(answers, function(value) {
if (value) {
@@ -71,11 +73,12 @@ angular.module('mm.addons.qtype_gapselect')
/**
* Check if two responses are the same.
*
+ * @param {Object} question Question.
* @param {Object} prevAnswers Previous answers.
* @param {Object} newAnswers New answers.
* @return {Boolean} True if same, false otherwise.
*/
- self.isSameResponse = function(prevAnswers, newAnswers) {
+ self.isSameResponse = function(question, prevAnswers, newAnswers) {
return $mmQuestion.compareAllAnswers(prevAnswers, newAnswers);
};
diff --git a/www/addons/qtype/match/handlers.js b/www/addons/qtype/match/handlers.js
index abf2263752e..03b12307d76 100644
--- a/www/addons/qtype/match/handlers.js
+++ b/www/addons/qtype/match/handlers.js
@@ -28,10 +28,11 @@ angular.module('mm.addons.qtype_match')
/**
* Check if a response is complete.
*
- * @param {Object} answers Question answers (without prefix).
- * @return {Mixed} True if complete, false if not complete, -1 if cannot determine.
+ * @param {Object} question Question.
+ * @param {Object} answers Question answers (without prefix).
+ * @return {Mixed} True if complete, false if not complete, -1 if cannot determine.
*/
- self.isCompleteResponse = function(answers) {
+ self.isCompleteResponse = function(question, answers) {
// We should always get a value for each select so we can assume we receive all the possible answers.
var isComplete = true;
angular.forEach(answers, function(value) {
@@ -55,10 +56,11 @@ angular.module('mm.addons.qtype_match')
* Check if a student has provided enough of an answer for the question to be graded automatically,
* or whether it must be considered aborted.
*
- * @param {Object} answers Question answers (without prefix).
- * @return {Mixed} True if gradable, false if not gradable, -1 if cannot determine.
+ * @param {Object} question Question.
+ * @param {Object} answers Question answers (without prefix).
+ * @return {Mixed} True if gradable, false if not gradable, -1 if cannot determine.
*/
- self.isGradableResponse = function(answers) {
+ self.isGradableResponse = function(question, answers) {
// We should always get a value for each select so we can assume we receive all the possible answers.
var isGradable = false;
angular.forEach(answers, function(value) {
@@ -72,11 +74,12 @@ angular.module('mm.addons.qtype_match')
/**
* Check if two responses are the same.
*
+ * @param {Object} question Question.
* @param {Object} prevAnswers Previous answers.
* @param {Object} newAnswers New answers.
* @return {Boolean} True if same, false otherwise.
*/
- self.isSameResponse = function(prevAnswers, newAnswers) {
+ self.isSameResponse = function(question, prevAnswers, newAnswers) {
return $mmQuestion.compareAllAnswers(prevAnswers, newAnswers);
};
diff --git a/www/addons/qtype/multianswer/handlers.js b/www/addons/qtype/multianswer/handlers.js
index 6e924d46a5a..42fbd378f53 100644
--- a/www/addons/qtype/multianswer/handlers.js
+++ b/www/addons/qtype/multianswer/handlers.js
@@ -21,26 +21,28 @@ angular.module('mm.addons.qtype_multianswer')
* @ngdoc service
* @name $mmaQtypeMultianswerHandler
*/
-.factory('$mmaQtypeMultianswerHandler', function($mmQuestion) {
+.factory('$mmaQtypeMultianswerHandler', function($mmQuestion, $mmQuestionHelper) {
var self = {};
/**
* Check if a response is complete.
*
- * @param {Object} answers Question answers (without prefix).
- * @return {Mixed} True if complete, false if not complete, -1 if cannot determine.
+ * @param {Object} question Question.
+ * @param {Object} answers Question answers (without prefix).
+ * @return {Mixed} True if complete, false if not complete, -1 if cannot determine.
*/
- self.isCompleteResponse = function(answers) {
- var hasReponse = false;
- angular.forEach(answers, function(value) {
- if (value || value === false) {
- hasReponse = true;
+ self.isCompleteResponse = function(question, answers) {
+ // Get all the inputs in the question to check if they've all been answered.
+ var names = $mmQuestion.getBasicAnswers($mmQuestionHelper.getAllInputNamesFromHtml(question.html));
+
+ for (var name in names) {
+ if (!answers[name] && answers[name] !== false && answers[name] !== 0) {
+ return false;
}
- });
+ }
- // We don't have the full list of subquestions, so we can't be sure they all have been answered.
- return hasReponse ? -1 : false;
+ return true;
};
/**
@@ -56,10 +58,11 @@ angular.module('mm.addons.qtype_multianswer')
* Check if a student has provided enough of an answer for the question to be graded automatically,
* or whether it must be considered aborted.
*
- * @param {Object} answers Question answers (without prefix).
- * @return {Mixed} True if gradable, false if not gradable, -1 if cannot determine.
+ * @param {Object} question Question.
+ * @param {Object} answers Question answers (without prefix).
+ * @return {Mixed} True if gradable, false if not gradable, -1 if cannot determine.
*/
- self.isGradableResponse = function(answers) {
+ self.isGradableResponse = function(question, answers) {
var hasReponse = false;
angular.forEach(answers, function(value) {
if (value || value === false) {
@@ -72,11 +75,12 @@ angular.module('mm.addons.qtype_multianswer')
/**
* Check if two responses are the same.
*
+ * @param {Object} question Question.
* @param {Object} prevAnswers Previous answers.
* @param {Object} newAnswers New answers.
* @return {Boolean} True if same, false otherwise.
*/
- self.isSameResponse = function(prevAnswers, newAnswers) {
+ self.isSameResponse = function(question, prevAnswers, newAnswers) {
return $mmQuestion.compareAllAnswers(prevAnswers, newAnswers);
};
diff --git a/www/addons/qtype/multichoice/handlers.js b/www/addons/qtype/multichoice/handlers.js
index 4314d92f601..066c79751b1 100644
--- a/www/addons/qtype/multichoice/handlers.js
+++ b/www/addons/qtype/multichoice/handlers.js
@@ -28,10 +28,11 @@ angular.module('mm.addons.qtype_multichoice')
/**
* Check if a response is complete.
*
- * @param {Object} answers Question answers (without prefix).
- * @return {Mixed} True if complete, false if not complete, -1 if cannot determine.
+ * @param {Object} question Question.
+ * @param {Object} answers Question answers (without prefix).
+ * @return {Mixed} True if complete, false if not complete, -1 if cannot determine.
*/
- self.isCompleteResponse = function(answers) {
+ self.isCompleteResponse = function(question, answers) {
var isSingle = true,
isMultiComplete = false;
@@ -57,8 +58,8 @@ angular.module('mm.addons.qtype_multichoice')
/**
* Check if a response is complete. Only for single answer.
*
- * @param {Object} answers Question answers (without prefix).
- * @return {Mixed} True if complete, false if not complete, -1 if cannot determine.
+ * @param {Object} answers Question answers (without prefix).
+ * @return {Mixed} True if complete, false if not complete, -1 if cannot determine.
*/
self.isCompleteResponseSingle = function(answers) {
return answers['answer'] && answers['answer'] !== '';
@@ -77,19 +78,20 @@ angular.module('mm.addons.qtype_multichoice')
* Check if a student has provided enough of an answer for the question to be graded automatically,
* or whether it must be considered aborted.
*
- * @param {Object} answers Question answers (without prefix).
- * @return {Mixed} True if gradable, false if not gradable, -1 if cannot determine.
+ * @param {Object} question Question.
+ * @param {Object} answers Question answers (without prefix).
+ * @return {Mixed} True if gradable, false if not gradable, -1 if cannot determine.
*/
- self.isGradableResponse = function(answers) {
- return self.isCompleteResponse(answers);
+ self.isGradableResponse = function(question, answers) {
+ return self.isCompleteResponse(question, answers);
};
/**
* Check if a student has provided enough of an answer for the question to be graded automatically,
* or whether it must be considered aborted. Only for single answer.
*
- * @param {Object} answers Question answers (without prefix).
- * @return {Mixed} True if gradable, false if not gradable, -1 if cannot determine.
+ * @param {Object} answers Question answers (without prefix).
+ * @return {Mixed} True if gradable, false if not gradable, -1 if cannot determine.
*/
self.isGradableResponseSingle = function(answers) {
return self.isCompleteResponseSingle(answers);
@@ -98,11 +100,12 @@ angular.module('mm.addons.qtype_multichoice')
/**
* Check if two responses are the same.
*
+ * @param {Object} question Question.
* @param {Object} prevAnswers Previous answers.
* @param {Object} newAnswers New answers.
* @return {Boolean} True if same, false otherwise.
*/
- self.isSameResponse = function(prevAnswers, newAnswers) {
+ self.isSameResponse = function(question, prevAnswers, newAnswers) {
var isSingle = true,
isMultiSame = true;
diff --git a/www/addons/qtype/numerical/handlers.js b/www/addons/qtype/numerical/handlers.js
index aeda7b92673..2a5f50358bd 100644
--- a/www/addons/qtype/numerical/handlers.js
+++ b/www/addons/qtype/numerical/handlers.js
@@ -28,11 +28,12 @@ angular.module('mm.addons.qtype_numerical')
/**
* Check if a response is complete.
*
- * @param {Object} answers Question answers (without prefix).
- * @return {Mixed} True if complete, false if not complete, -1 if cannot determine.
+ * @param {Object} question Question.
+ * @param {Object} answers Question answers (without prefix).
+ * @return {Mixed} True if complete, false if not complete, -1 if cannot determine.
*/
- self.isCompleteResponse = function(answers) {
- if (!self.isGradableResponse(answers) || !self.validateUnits(answers['answer'])) {
+ self.isCompleteResponse = function(question, answers) {
+ if (!self.isGradableResponse(question, answers) || !self.validateUnits(answers['answer'])) {
return false;
}
@@ -52,21 +53,23 @@ angular.module('mm.addons.qtype_numerical')
* Check if a student has provided enough of an answer for the question to be graded automatically,
* or whether it must be considered aborted.
*
- * @param {Object} answers Question answers (without prefix).
- * @return {Mixed} True if gradable, false if not gradable, -1 if cannot determine.
+ * @param {Object} question Question.
+ * @param {Object} answers Question answers (without prefix).
+ * @return {Mixed} True if gradable, false if not gradable, -1 if cannot determine.
*/
- self.isGradableResponse = function(answers) {
+ self.isGradableResponse = function(question, answers) {
return answers['answer'] || answers['answer'] === '0' || answers['answer'] === 0;
};
/**
* Check if two responses are the same.
*
+ * @param {Object} question Question.
* @param {Object} prevAnswers Previous answers.
* @param {Object} newAnswers New answers.
* @return {Boolean} True if same, false otherwise.
*/
- self.isSameResponse = function(prevAnswers, newAnswers) {
+ self.isSameResponse = function(question, prevAnswers, newAnswers) {
return $mmUtil.sameAtKeyMissingIsBlank(prevAnswers, newAnswers, 'answer');
};
diff --git a/www/addons/qtype/randomsamatch/handlers.js b/www/addons/qtype/randomsamatch/handlers.js
index 73f1fcb5898..47dada28862 100644
--- a/www/addons/qtype/randomsamatch/handlers.js
+++ b/www/addons/qtype/randomsamatch/handlers.js
@@ -28,12 +28,13 @@ angular.module('mm.addons.qtype_randomsamatch')
/**
* Check if a response is complete.
*
- * @param {Object} answers Question answers (without prefix).
- * @return {Mixed} True if complete, false if not complete, -1 if cannot determine.
+ * @param {Object} question Question.
+ * @param {Object} answers Question answers (without prefix).
+ * @return {Mixed} True if complete, false if not complete, -1 if cannot determine.
*/
- self.isCompleteResponse = function(answers) {
+ self.isCompleteResponse = function(question, answers) {
// This question type depends on match.
- return $mmaQtypeMatchHandler.isCompleteResponse(answers);
+ return $mmaQtypeMatchHandler.isCompleteResponse(question, answers);
};
/**
@@ -49,24 +50,26 @@ angular.module('mm.addons.qtype_randomsamatch')
* Check if a student has provided enough of an answer for the question to be graded automatically,
* or whether it must be considered aborted.
*
- * @param {Object} answers Question answers (without prefix).
- * @return {Mixed} True if gradable, false if not gradable, -1 if cannot determine.
+ * @param {Object} question Question.
+ * @param {Object} answers Question answers (without prefix).
+ * @return {Mixed} True if gradable, false if not gradable, -1 if cannot determine.
*/
- self.isGradableResponse = function(answers) {
+ self.isGradableResponse = function(question, answers) {
// This question type depends on match.
- return $mmaQtypeMatchHandler.isGradableResponse(answers);
+ return $mmaQtypeMatchHandler.isGradableResponse(question, answers);
};
/**
* Check if two responses are the same.
*
+ * @param {Object} question Question.
* @param {Object} prevAnswers Previous answers.
* @param {Object} newAnswers New answers.
* @return {Boolean} True if same, false otherwise.
*/
- self.isSameResponse = function(prevAnswers, newAnswers) {
+ self.isSameResponse = function(question, prevAnswers, newAnswers) {
// This question type depends on match.
- return $mmaQtypeMatchHandler.isSameResponse(prevAnswers, newAnswers);
+ return $mmaQtypeMatchHandler.isSameResponse(question, prevAnswers, newAnswers);
};
/**
diff --git a/www/addons/qtype/shortanswer/handlers.js b/www/addons/qtype/shortanswer/handlers.js
index 22d48dec107..af5f966dd16 100644
--- a/www/addons/qtype/shortanswer/handlers.js
+++ b/www/addons/qtype/shortanswer/handlers.js
@@ -28,10 +28,11 @@ angular.module('mm.addons.qtype_shortanswer')
/**
* Check if a response is complete.
*
- * @param {Object} answers Question answers (without prefix).
- * @return {Mixed} True if complete, false if not complete, -1 if cannot determine.
+ * @param {Object} question Question.
+ * @param {Object} answers Question answers (without prefix).
+ * @return {Mixed} True if complete, false if not complete, -1 if cannot determine.
*/
- self.isCompleteResponse = function(answers) {
+ self.isCompleteResponse = function(question, answers) {
return answers['answer'] || answers['answer'] === 0;
};
@@ -48,21 +49,23 @@ angular.module('mm.addons.qtype_shortanswer')
* Check if a student has provided enough of an answer for the question to be graded automatically,
* or whether it must be considered aborted.
*
- * @param {Object} answers Question answers (without prefix).
- * @return {Mixed} True if gradable, false if not gradable, -1 if cannot determine.
+ * @param {Object} question Question.
+ * @param {Object} answers Question answers (without prefix).
+ * @return {Mixed} True if gradable, false if not gradable, -1 if cannot determine.
*/
- self.isGradableResponse = function(answers) {
- return self.isCompleteResponse(answers);
+ self.isGradableResponse = function(question, answers) {
+ return self.isCompleteResponse(question, answers);
};
/**
* Check if two responses are the same.
*
+ * @param {Object} question Question.
* @param {Object} prevAnswers Previous answers.
* @param {Object} newAnswers New answers.
* @return {Boolean} True if same, false otherwise.
*/
- self.isSameResponse = function(prevAnswers, newAnswers) {
+ self.isSameResponse = function(question, prevAnswers, newAnswers) {
return $mmUtil.sameAtKeyMissingIsBlank(prevAnswers, newAnswers, 'answer');
};
diff --git a/www/addons/qtype/truefalse/handlers.js b/www/addons/qtype/truefalse/handlers.js
index 82ae0f3eb42..d58bc4dc73d 100644
--- a/www/addons/qtype/truefalse/handlers.js
+++ b/www/addons/qtype/truefalse/handlers.js
@@ -28,10 +28,11 @@ angular.module('mm.addons.qtype_truefalse')
/**
* Check if a response is complete.
*
- * @param {Object} answers Question answers (without prefix).
- * @return {Mixed} True if complete, false if not complete, -1 if cannot determine.
+ * @param {Object} question Question.
+ * @param {Object} answers Question answers (without prefix).
+ * @return {Mixed} True if complete, false if not complete, -1 if cannot determine.
*/
- self.isCompleteResponse = function(answers) {
+ self.isCompleteResponse = function(question, answers) {
return !!answers['answer'];
};
@@ -48,21 +49,23 @@ angular.module('mm.addons.qtype_truefalse')
* Check if a student has provided enough of an answer for the question to be graded automatically,
* or whether it must be considered aborted.
*
- * @param {Object} answers Question answers (without prefix).
- * @return {Mixed} True if gradable, false if not gradable, -1 if cannot determine.
+ * @param {Object} question Question.
+ * @param {Object} answers Question answers (without prefix).
+ * @return {Mixed} True if gradable, false if not gradable, -1 if cannot determine.
*/
- self.isGradableResponse = function(answers) {
- return self.isCompleteResponse(answers);
+ self.isGradableResponse = function(question, answers) {
+ return self.isCompleteResponse(question, answers);
};
/**
* Check if two responses are the same.
*
+ * @param {Object} question Question.
* @param {Object} prevAnswers Previous answers.
* @param {Object} newAnswers New answers.
* @return {Boolean} True if same, false otherwise.
*/
- self.isSameResponse = function(prevAnswers, newAnswers) {
+ self.isSameResponse = function(question, prevAnswers, newAnswers) {
return $mmUtil.sameAtKeyMissingIsBlank(prevAnswers, newAnswers, 'answer');
};
diff --git a/www/core/components/question/lang/en.json b/www/core/components/question/lang/en.json
index 33c3418e7f2..3dd8f89c385 100644
--- a/www/core/components/question/lang/en.json
+++ b/www/core/components/question/lang/en.json
@@ -4,6 +4,7 @@
"certainty": "Certainty",
"complete": "Complete",
"correct": "Correct",
+ "errorattachmentsnotsupported": "The application doesn't support attaching files to answers yet.",
"errorquestionnotsupported": "This type of question isn't supported by the app in your site: {{$a}}.",
"feedback": "Feedback",
"howtodraganddrop": "Tap to select then tap to drop.",
@@ -12,6 +13,7 @@
"notanswered": "Not answered",
"notyetanswered": "Not yet answered",
"partiallycorrect": "Partially correct",
+ "questionmessage": "Question {{$a}}: {{$b}}",
"requiresgrading": "Requires grading",
"unknown": "Cannot determine status"
}
diff --git a/www/core/components/question/scss/styles.scss b/www/core/components/question/scss/styles.scss
index 81efa0a2f2d..6828cf8b249 100644
--- a/www/core/components/question/scss/styles.scss
+++ b/www/core/components/question/scss/styles.scss
@@ -4,6 +4,7 @@ $mm-question-incorrect-color: #b94a48 !default;
$mm-question-state-correct-color: #cfc !default;
$mm-question-state-partial-color: #ffa !default;
$mm-question-state-incorrect-color: #fcc !default;
+$mm-question-warning-color: #c00 !default;
.mm-question-textarea {
width: 100%;
@@ -97,3 +98,7 @@ li.mm-question-answer-incorrect,
background-color: $mm-question-state-incorrect-color;
}
}
+
+.mm-question-warning, p.mm-question-warning, .item .mm-question-warning {
+ color: $mm-question-warning-color;
+}
diff --git a/www/core/components/question/services/delegate.js b/www/core/components/question/services/delegate.js
index c854d4b3878..9c55afb76cc 100644
--- a/www/core/components/question/services/delegate.js
+++ b/www/core/components/question/services/delegate.js
@@ -53,16 +53,23 @@ angular.module('mm.core.question')
* @param {String|Object|Function} handler Must be resolved to an object defining the following properties. Or to a function
* returning an object defining these properties. See {@link $mmUtil#resolveObject}.
* - isEnabled (Boolean|Promise) Whether or not the handler is enabled on a site level.
- * When using a promise, it should return a boolean.
+ * When using a promise, it should return a boolean.
* - getDirectiveName(question) (String) Returns the name of the directive to render the question.
- * There's no need to check the question type in this function.
+ * There's no need to check the question type in this function.
* - getBehaviour(question, behaviour) (String) Optional. Returns the name of the behaviour to use
- * for the question. If the question should use the default behaviour
- * you shouldn't implement this question or it should just return
- * the behaviour param.
+ * for the question. If the question should use the default behaviour you
+ * shouldn't implement this function.
* - validateSequenceCheck(question, offlineSeqCheck) (Boolean) Optional. Validate if an offline
- * sequencecheck is valid compared with the online one. This function
- * only needs to be implemented if a specific compare is required.
+ * sequencecheck is valid compared with the online one. This function only
+ * needs to be implemented if a specific compare is required.
+ * - isCompleteResponse(question, answers) (Mixed) Optional. Check if a response is complete.
+ * Return true if complete, false if not complete, -1 if cannot determine.
+ * - isGradableResponse(question, answers) (Mixed) Optional. Check if a student has provided enough
+ * of an answer for the question to be graded automatically, or whether it must
+ * be considered aborted.
+ * Return true if gradable, false if not gradable, -1 if cannot determine.
+ * - isSameResponse(question, prevAnswers, newAnswers) (Boolean) Optional. Check if two responses
+ * are equal. Always return boolean.
*/
self.registerHandler = function(name, questionType, handler) {
if (typeof handlers[questionType] !== 'undefined') {
@@ -123,6 +130,24 @@ angular.module('mm.core.question')
}
};
+ /**
+ * Check if a question can be submitted.
+ * If a question cannot be submitted it should return a message explaining why (translated or not).
+ *
+ * @module mm.core.question
+ * @ngdoc method
+ * @name $mmQuestionDelegate#getPreventSubmitMessage
+ * @param {Object} question Question.
+ * @return {String} Prevent submit message. Undefined or empty if cannot be submitted.
+ */
+ self.getPreventSubmitMessage = function(question) {
+ var type = 'qtype_' + question.type,
+ handler = enabledHandlers[type];
+ if (typeof handler != 'undefined' && handler.getPreventSubmitMessage) {
+ return handler.getPreventSubmitMessage(question);
+ }
+ };
+
/**
* Check if a response is complete.
*
@@ -136,7 +161,7 @@ angular.module('mm.core.question')
var type = 'qtype_' + question.type;
if (typeof enabledHandlers[type] != 'undefined') {
if (enabledHandlers[type].isCompleteResponse) {
- return enabledHandlers[type].isCompleteResponse(answers);
+ return enabledHandlers[type].isCompleteResponse(question, answers);
}
}
return -1;
@@ -156,7 +181,7 @@ angular.module('mm.core.question')
var type = 'qtype_' + question.type;
if (typeof enabledHandlers[type] != 'undefined') {
if (enabledHandlers[type].isGradableResponse) {
- return enabledHandlers[type].isGradableResponse(answers);
+ return enabledHandlers[type].isGradableResponse(question, answers);
}
}
return -1;
@@ -177,7 +202,7 @@ angular.module('mm.core.question')
var type = 'qtype_' + question.type;
if (typeof enabledHandlers[type] != 'undefined') {
if (enabledHandlers[type].isSameResponse) {
- return enabledHandlers[type].isSameResponse(prevAnswers, newAnswers);
+ return enabledHandlers[type].isSameResponse(question, prevAnswers, newAnswers);
}
}
return false;
diff --git a/www/core/components/question/services/helper.js b/www/core/components/question/services/helper.js
index 4f12fec1bf1..20167498568 100644
--- a/www/core/components/question/services/helper.js
+++ b/www/core/components/question/services/helper.js
@@ -363,6 +363,37 @@ angular.module('mm.core.question')
}
};
+ /**
+ * Get the names of all the inputs inside an HTML code.
+ * This function will return an object where the keys are the input names. The values will always be true.
+ * This is in order to make this function compatible with other functions like $mmQuestion#getBasicAnswers.
+ *
+ * @module mm.core.question
+ * @ngdoc method
+ * @name $mmQuestionHelper#getAllInputNamesFromHtml
+ * @param {String} html HTML code.
+ * @return {Object} Object where the keys are the names.
+ */
+ self.getAllInputNamesFromHtml = function(html) {
+ var form = document.createElement('form'),
+ answers = {};
+
+ form.innerHTML = html;
+
+ // Search all input elements.
+ angular.forEach(form.elements, function(element) {
+ var name = element.name || '';
+ // Ignore flag and submit inputs.
+ if (!name || name.match(/_:flagged$/) || element.type == 'submit' || element.tagName == 'BUTTON') {
+ return;
+ }
+
+ answers[$mmQuestion.removeQuestionPrefix(name)] = true;
+ });
+
+ return answers;
+ };
+
/**
* Retrieve the answers entered in a form.
* We don't use ng-model because it doesn't detect changes done by JavaScript and some questions might do that.
@@ -411,7 +442,7 @@ angular.module('mm.core.question')
* @ngdoc method
* @name $mmQuestionHelper#getQuestionAttachmentsFromHtml
* @param {String} html HTML code to search in.
- * @return {[type]} [description]
+ * @return {Object[]} Attachments.
*/
self.getQuestionAttachmentsFromHtml = function(html) {
var el = angular.element('
'),
@@ -422,6 +453,9 @@ angular.module('mm.core.question')
el.html(html);
el = el[0];
+ // Remove the filemanager (area to attach files to a question).
+ $mmUtil.removeElement(el, 'div[id*=filemanager]');
+
// Search the anchors.
anchors = el.querySelectorAll('a');
angular.forEach(anchors, function(anchor) {
diff --git a/www/core/components/question/services/question.js b/www/core/components/question/services/question.js
index ebf2639736e..43fabc2d781 100644
--- a/www/core/components/question/services/question.js
+++ b/www/core/components/question/services/question.js
@@ -447,13 +447,16 @@ angular.module('mm.core.question')
/**
* Check if an answer is extra data like sequencecheck or certainty.
*
+ * @module mm.core.question
+ * @ngdoc method
+ * @name $mmQuestion#isExtraAnswer
* @param {String} name Answer name.
* @return {Boolean} True if extra data, false otherwise.
*/
self.isExtraAnswer = function(name) {
// Maybe the name still has the prefix.
name = self.removeQuestionPrefix(name);
- return name[0] == '-' || name == ':';
+ return name[0] == '-' || name[0] == ':';
};
/**
diff --git a/www/core/scss/styles.scss b/www/core/scss/styles.scss
index fbc2bf00e96..fdb82cd9cce 100644
--- a/www/core/scss/styles.scss
+++ b/www/core/scss/styles.scss
@@ -74,6 +74,11 @@ em {
@extend h2;
}
+.item.item-text-wrap .item-heading {
+ overflow: visible;
+ white-space: normal;
+}
+
// More options for grids.
.col-65 {
@include flex(0, 0, 65%);
@@ -389,6 +394,10 @@ mm-timer {
}
}
+.mm-monospaced {
+ font-family: Andale Mono,Monaco,Courier New,DejaVu Sans Mono,monospace;
+}
+
/**
* This CSS uses adjacent selectors instead of general sibling (~) selectors
* for ion radio that are broken in iOS 9 UIWebView.