Index: lams_central/conf/language/lams/ApplicationResources.properties =================================================================== diff -u -rd578cfde655760533b6ede422e7cf675a8c4ca6d -rf0ff6bc30e8fa7e5d4201b7b9571194845ad3a83 --- lams_central/conf/language/lams/ApplicationResources.properties (.../ApplicationResources.properties) (revision d578cfde655760533b6ede422e7cf675a8c4ca6d) +++ lams_central/conf/language/lams/ApplicationResources.properties (.../ApplicationResources.properties) (revision f0ff6bc30e8fa7e5d4201b7b9571194845ad3a83) @@ -1001,6 +1001,7 @@ label.authoring.short.answer.yes.case.must.match = Yes, case must match label.authoring.short.answer.case.sensitivity = Case sensitivity label.authoring.short.answer.add.answer = Add another answer +label.authoring.short.answer.exact.match = Learner answer must exactly match expected answer label.authoring.true.false.question = True/False question label.authoring.true.false.correct.answer = Correct answer label.authoring.true.false.feedback.on.true = Feedback for the response 'True'. Index: lams_central/src/java/org/lamsfoundation/lams/web/qb/EditQbQuestionController.java =================================================================== diff -u -rd4ca48e53c792f5021279765d8263ebdbd516339 -rf0ff6bc30e8fa7e5d4201b7b9571194845ad3a83 --- lams_central/src/java/org/lamsfoundation/lams/web/qb/EditQbQuestionController.java (.../EditQbQuestionController.java) (revision d4ca48e53c792f5021279765d8263ebdbd516339) +++ lams_central/src/java/org/lamsfoundation/lams/web/qb/EditQbQuestionController.java (.../EditQbQuestionController.java) (revision f0ff6bc30e8fa7e5d4201b7b9571194845ad3a83) @@ -135,6 +135,7 @@ form.setShuffle(qbQuestion.isShuffle()); form.setPrefixAnswersWithLetters(qbQuestion.isPrefixAnswersWithLetters()); form.setCaseSensitive(qbQuestion.isCaseSensitive()); + form.setExactMatch(qbQuestion.isExactMatch()); form.setCorrectAnswer(qbQuestion.getCorrectAnswer()); form.setAllowRichEditor(qbQuestion.isAllowRichEditor()); form.setMaxWordsLimit(qbQuestion.getMaxWordsLimit()); Index: lams_central/web/qb/authoring/addVsa.jsp =================================================================== diff -u -re2a265f5d454af5c8e05cc4d0fc0b635a8cb6d1b -rf0ff6bc30e8fa7e5d4201b7b9571194845ad3a83 --- lams_central/web/qb/authoring/addVsa.jsp (.../addVsa.jsp) (revision e2a265f5d454af5c8e05cc4d0fc0b635a8cb6d1b) +++ lams_central/web/qb/authoring/addVsa.jsp (.../addVsa.jsp) (revision f0ff6bc30e8fa7e5d4201b7b9571194845ad3a83) @@ -190,6 +190,16 @@
+ +
+ +
+ Index: lams_common/src/java/org/lamsfoundation/lams/dbupdates/patch20220411.sql =================================================================== diff -u --- lams_common/src/java/org/lamsfoundation/lams/dbupdates/patch20220411.sql (revision 0) +++ lams_common/src/java/org/lamsfoundation/lams/dbupdates/patch20220411.sql (revision f0ff6bc30e8fa7e5d4201b7b9571194845ad3a83) @@ -0,0 +1,15 @@ +-- Turn off autocommit, so nothing is committed if there is an error +SET AUTOCOMMIT = 0; +SET FOREIGN_KEY_CHECKS=0; +-- Put all sql statements below here + +--LDEV-5307 Allow exact matching of VSAs + +ALTER TABLE lams_qb_question ADD COLUMN exact_match TINYINT NOT NULL DEFAULT 0 AFTER case_sensitive; + +-- Put all sql statements above here + +-- If there were no errors, commit and restore autocommit to on +COMMIT; +SET AUTOCOMMIT = 1; +SET FOREIGN_KEY_CHECKS=1; Index: lams_common/src/java/org/lamsfoundation/lams/qb/QbUtils.java =================================================================== diff -u -rb0a4fbc85e1574ef3efe06a1020b84e2d7c7a75e -rf0ff6bc30e8fa7e5d4201b7b9571194845ad3a83 --- lams_common/src/java/org/lamsfoundation/lams/qb/QbUtils.java (.../QbUtils.java) (revision b0a4fbc85e1574ef3efe06a1020b84e2d7c7a75e) +++ lams_common/src/java/org/lamsfoundation/lams/qb/QbUtils.java (.../QbUtils.java) (revision f0ff6bc30e8fa7e5d4201b7b9571194845ad3a83) @@ -89,29 +89,31 @@ form.setOldCollectionUid(collectionUid); } - public static String normaliseVSAnswer(String answer) { + public static String normaliseVSAnswer(String answer, boolean isExactMatch) { if (StringUtils.isBlank(answer)) { return null; } - String normalisedAnswer = answer.replaceAll(VSA_ANSWER_NORMALISE_JAVA_REG_EXP, ""); + String normalisedAnswer = isExactMatch ? answer.strip() + : answer.replaceAll(VSA_ANSWER_NORMALISE_JAVA_REG_EXP, ""); if (StringUtils.isBlank(normalisedAnswer)) { return null; } return normalisedAnswer; } - public static Set normaliseVSOption(String option) { + public static Set normaliseVSOption(String option, boolean isExactMatch) { return StringUtils.isBlank(option) ? Set.of() : Stream.of(option.split(VSA_ANSWER_DELIMITER)).filter(StringUtils::isNotBlank) - .map(answer -> QbUtils.normaliseVSAnswer(answer)).filter(StringUtils::isNotBlank) + .map(answer -> QbUtils.normaliseVSAnswer(answer, isExactMatch)).filter(StringUtils::isNotBlank) .collect(Collectors.toCollection(LinkedHashSet::new)); } - public static boolean isVSAnswerAllocated(String option, String normalisedAnswer, boolean isCaseSensitive) { + public static boolean isVSAnswerAllocated(String option, String normalisedAnswer, boolean isCaseSensitive, + boolean isExactMatch) { if (StringUtils.isBlank(option) || StringUtils.isBlank(normalisedAnswer)) { return false; } - return QbUtils.normaliseVSOption(option).stream() + return QbUtils.normaliseVSOption(option, isExactMatch).stream() .anyMatch(s -> isCaseSensitive ? s.equals(normalisedAnswer) : s.equalsIgnoreCase(normalisedAnswer)); } @@ -122,7 +124,9 @@ * is an accumulator for unallocated answers so they do not appear in VSA allocation UI twice */ public static boolean isVSAnswerAllocated(QbQuestion qbQuestion, String answer, Set notAllocatedAnswers) { - String normalisedAnswer = QbUtils.normaliseVSAnswer(answer); + boolean isExactMatch = qbQuestion.isExactMatch(); + + String normalisedAnswer = QbUtils.normaliseVSAnswer(answer, isExactMatch); if (StringUtils.isBlank(normalisedAnswer)) { return false; } @@ -132,7 +136,8 @@ for (QbOption option : qbQuestion.getQbOptions()) { String name = option.getName(); - isAnswerAllocated = QbUtils.isVSAnswerAllocated(name, normalisedAnswer, isQuestionCaseSensitive); + isAnswerAllocated = QbUtils.isVSAnswerAllocated(name, normalisedAnswer, isQuestionCaseSensitive, + isExactMatch); if (isAnswerAllocated) { break; } Index: lams_common/src/java/org/lamsfoundation/lams/qb/form/QbQuestionForm.java =================================================================== diff -u -r6bab11b98a1dfdcebfb7e11b8dcfab3128a2ff83 -rf0ff6bc30e8fa7e5d4201b7b9571194845ad3a83 --- lams_common/src/java/org/lamsfoundation/lams/qb/form/QbQuestionForm.java (.../QbQuestionForm.java) (revision 6bab11b98a1dfdcebfb7e11b8dcfab3128a2ff83) +++ lams_common/src/java/org/lamsfoundation/lams/qb/form/QbQuestionForm.java (.../QbQuestionForm.java) (revision f0ff6bc30e8fa7e5d4201b7b9571194845ad3a83) @@ -56,6 +56,7 @@ private boolean shuffle; private boolean prefixAnswersWithLetters; private boolean caseSensitive; + private boolean exactMatch; private boolean correctAnswer; private boolean allowRichEditor; private int maxWordsLimit; @@ -216,6 +217,14 @@ this.caseSensitive = caseSensitive; } + public boolean isExactMatch() { + return exactMatch; + } + + public void setExactMatch(boolean exactMatch) { + this.exactMatch = exactMatch; + } + public boolean isCorrectAnswer() { return correctAnswer; } Index: lams_common/src/java/org/lamsfoundation/lams/qb/model/QbQuestion.java =================================================================== diff -u -r59390e4bf349a52e22884134d890724cac1440be -rf0ff6bc30e8fa7e5d4201b7b9571194845ad3a83 --- lams_common/src/java/org/lamsfoundation/lams/qb/model/QbQuestion.java (.../QbQuestion.java) (revision 59390e4bf349a52e22884134d890724cac1440be) +++ lams_common/src/java/org/lamsfoundation/lams/qb/model/QbQuestion.java (.../QbQuestion.java) (revision f0ff6bc30e8fa7e5d4201b7b9571194845ad3a83) @@ -130,6 +130,9 @@ @Column(name = "case_sensitive") private boolean caseSensitive; + @Column(name = "exact_match") + private boolean exactMatch; + @Column(name = "correct_answer") private boolean correctAnswer; @@ -448,6 +451,14 @@ this.caseSensitive = caseSensitive; } + public boolean isExactMatch() { + return exactMatch; + } + + public void setExactMatch(boolean exactMatch) { + this.exactMatch = exactMatch; + } + public boolean getCorrectAnswer() { return correctAnswer; } Index: lams_common/src/java/org/lamsfoundation/lams/qb/service/QbService.java =================================================================== diff -u -rb0a4fbc85e1574ef3efe06a1020b84e2d7c7a75e -rf0ff6bc30e8fa7e5d4201b7b9571194845ad3a83 --- lams_common/src/java/org/lamsfoundation/lams/qb/service/QbService.java (.../QbService.java) (revision b0a4fbc85e1574ef3efe06a1020b84e2d7c7a75e) +++ lams_common/src/java/org/lamsfoundation/lams/qb/service/QbService.java (.../QbService.java) (revision f0ff6bc30e8fa7e5d4201b7b9571194845ad3a83) @@ -815,14 +815,16 @@ @Override public Long allocateVSAnswerToOption(Long toolQuestionUid, Long targetOptionUid, Long previousOptionUid, String answer) { - String normalisedAnswer = QbUtils.normaliseVSAnswer(answer); + QbToolQuestion toolQuestion = qbDAO.find(QbToolQuestion.class, toolQuestionUid); + QbQuestion qbQuestion = toolQuestion.getQbQuestion(); + boolean isExactMatch = qbQuestion.isExactMatch(); + + String normalisedAnswer = QbUtils.normaliseVSAnswer(answer, isExactMatch); if (normalisedAnswer == null && previousOptionUid.equals(-1L)) { return null; } answer = answer.strip(); - QbToolQuestion toolQuestion = qbDAO.find(QbToolQuestion.class, toolQuestionUid); - QbQuestion qbQuestion = toolQuestion.getQbQuestion(); Long qbQuestionUid = qbQuestion.getUid(); boolean isQuestionCaseSensitive = qbQuestion.isCaseSensitive(); @@ -834,8 +836,8 @@ if (previousOptionUid.equals(-1L)) { // new allocation, check if the answer was not allocated anywhere already String name = option.getName(); - boolean isAnswerAllocated = QbUtils.isVSAnswerAllocated(name, normalisedAnswer, - isQuestionCaseSensitive); + boolean isAnswerAllocated = QbUtils.isVSAnswerAllocated(name, normalisedAnswer, isQuestionCaseSensitive, + isExactMatch); if (isAnswerAllocated) { return option.getUid(); } @@ -862,7 +864,7 @@ Set nameWithoutUserAnswer = new LinkedHashSet<>(List.of(alternatives)); nameWithoutUserAnswer.remove(answer); name = nameWithoutUserAnswer.isEmpty() ? "" - : nameWithoutUserAnswer.stream().filter(a -> QbUtils.normaliseVSAnswer(a) != null) + : nameWithoutUserAnswer.stream().filter(a -> QbUtils.normaliseVSAnswer(a, isExactMatch) != null) .collect(Collectors.joining(QbUtils.VSA_ANSWER_DELIMITER)); previousOption.setName(name); qbDAO.update(previousOption); @@ -877,7 +879,8 @@ if (targetOption != null) { String name = targetOption.getName(); - boolean isAnswerAllocated = QbUtils.isVSAnswerAllocated(name, normalisedAnswer, isQuestionCaseSensitive); + boolean isAnswerAllocated = QbUtils.isVSAnswerAllocated(name, normalisedAnswer, isQuestionCaseSensitive, + isExactMatch); if (isAnswerAllocated) { // the answer has been already allocated to the target option return targetOptionUid; @@ -945,6 +948,7 @@ } else if ((type == QbQuestion.TYPE_VERY_SHORT_ANSWERS)) { qbQuestion.setPenaltyFactor(Float.parseFloat(form.getPenaltyFactor())); qbQuestion.setCaseSensitive(form.isCaseSensitive()); + qbQuestion.setExactMatch(form.isExactMatch()); qbQuestion.setAutocompleteEnabled(form.isAutocompleteEnabled()); } else if ((type == QbQuestion.TYPE_NUMERICAL)) { Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/dao/hibernate/AssessmentResultDAOHibernate.java =================================================================== diff -u -rb8e5c281efce81034ea2675a610ba3ea8faa41fb -rf0ff6bc30e8fa7e5d4201b7b9571194845ad3a83 --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/dao/hibernate/AssessmentResultDAOHibernate.java (.../AssessmentResultDAOHibernate.java) (revision b8e5c281efce81034ea2675a610ba3ea8faa41fb) +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/dao/hibernate/AssessmentResultDAOHibernate.java (.../AssessmentResultDAOHibernate.java) (revision f0ff6bc30e8fa7e5d4201b7b9571194845ad3a83) @@ -174,16 +174,18 @@ + (parentOrganisation == null ? "" : " OR l.organisation.organisationId = :parentOrganisationId OR " + "l.organisation.parentOrganisation.organisationId = :parentOrganisationId") - + ") AND qr.qbToolQuestion.qbQuestion.uid = :qbQuestionUid AND REGEXP_REPLACE(qr.answer, '" - + QbUtils.VSA_ANSWER_NORMALISE_SQL_REG_EXP + "', '') = :answer ORDER BY r.startDate ASC"; + + ") AND qr.qbToolQuestion.qbQuestion.uid = :qbQuestionUid AND " + + (qbToolQuestion.getQbQuestion().isExactMatch() ? "TRIM(qr.answer)" + : "REGEXP_REPLACE(qr.answer, '" + QbUtils.VSA_ANSWER_NORMALISE_SQL_REG_EXP + "', '')") + + " = :answer ORDER BY r.startDate ASC"; Query q = getSession().createQuery(FIND_BY_QBQUESTION, AssessmentResult.class); q.setParameter("qbQuestionUid", qbToolQuestion.getQbQuestion().getUid()); q.setParameter("organisationId", organisation.getOrganisationId()); if (parentOrganisation != null) { q.setParameter("parentOrganisationId", parentOrganisation.getOrganisationId()); } - String normalisedAnswer = QbUtils.normaliseVSAnswer(answer); + String normalisedAnswer = QbUtils.normaliseVSAnswer(answer, qbToolQuestion.getQbQuestion().isExactMatch()); q.setParameter("answer", normalisedAnswer); return q.list(); } Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/dto/QuestionDTO.java =================================================================== diff -u -r236d0e362fd2af8ffee9d0f447bf148063bd5497 -rf0ff6bc30e8fa7e5d4201b7b9571194845ad3a83 --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/dto/QuestionDTO.java (.../QuestionDTO.java) (revision 236d0e362fd2af8ffee9d0f447bf148063bd5497) +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/dto/QuestionDTO.java (.../QuestionDTO.java) (revision f0ff6bc30e8fa7e5d4201b7b9571194845ad3a83) @@ -51,6 +51,8 @@ private boolean caseSensitive; + private boolean exactMatch; + private boolean correctAnswer; private boolean allowRichEditor; @@ -139,6 +141,7 @@ this.shuffle = qbQuestion.isShuffle(); this.prefixAnswersWithLetters = qbQuestion.isPrefixAnswersWithLetters(); this.caseSensitive = qbQuestion.isCaseSensitive(); + this.exactMatch = qbQuestion.isExactMatch(); this.correctAnswer = qbQuestion.getCorrectAnswer(); this.allowRichEditor = qbQuestion.isAllowRichEditor(); this.maxWordsLimit = qbQuestion.getMaxWordsLimit(); @@ -296,6 +299,14 @@ this.caseSensitive = caseSensitive; } + public boolean isExactMatch() { + return exactMatch; + } + + public void setExactMatch(boolean exactMatch) { + this.exactMatch = exactMatch; + } + public boolean getCorrectAnswer() { return correctAnswer; } Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/AssessmentServiceImpl.java =================================================================== diff -u -rb8e5c281efce81034ea2675a610ba3ea8faa41fb -rf0ff6bc30e8fa7e5d4201b7b9571194845ad3a83 --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/AssessmentServiceImpl.java (.../AssessmentServiceImpl.java) (revision b8e5c281efce81034ea2675a610ba3ea8faa41fb) +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/AssessmentServiceImpl.java (.../AssessmentServiceImpl.java) (revision f0ff6bc30e8fa7e5d4201b7b9571194845ad3a83) @@ -842,14 +842,15 @@ if (questionDto.getAnswer() != null) { boolean isQuestionCaseSensitive = questionDto.isCaseSensitive(); - String normalisedQuestionAnswer = QbUtils.normaliseVSAnswer(questionDto.getAnswer()); + boolean isExactMatch = questionDto.isExactMatch(); + String normalisedQuestionAnswer = QbUtils.normaliseVSAnswer(questionDto.getAnswer(), isExactMatch); for (OptionDTO optionDto : questionDto.getOptionDtos()) { // refresh latest answers from DB QbOption qbOption = qbService.getOptionByUid(optionDto.getUid()); optionDto.setName(qbOption.getName()); boolean isAnswerAllocated = QbUtils.isVSAnswerAllocated(qbOption.getName(), - normalisedQuestionAnswer, isQuestionCaseSensitive); + normalisedQuestionAnswer, isQuestionCaseSensitive, isExactMatch); if (isAnswerAllocated) { mark = optionDto.getMaxMark() * maxMark; @@ -1437,7 +1438,7 @@ for (AssessmentQuestionResult questionResult : allQuestionResults) { String answer = questionResult.getAnswer(); - if (QbUtils.normaliseVSAnswer(answer) == null) { + if (QbUtils.normaliseVSAnswer(answer, qbQuestion.isExactMatch()) == null) { continue; } @@ -3735,6 +3736,7 @@ qbQuestion.setAllowRichEditor( JsonUtil.optBoolean(questionJSONData, RestTags.ALLOW_RICH_TEXT_EDITOR, Boolean.FALSE)); qbQuestion.setCaseSensitive(JsonUtil.optBoolean(questionJSONData, "caseSensitive", Boolean.FALSE)); + qbQuestion.setExactMatch(JsonUtil.optBoolean(questionJSONData, "exactMatch", Boolean.FALSE)); qbQuestion.setCorrectAnswer(JsonUtil.optBoolean(questionJSONData, "correctAnswer", Boolean.FALSE)); qbQuestion.setFeedback(JsonUtil.optString(questionJSONData, "feedback")); qbQuestion.setFeedbackOnCorrect(JsonUtil.optString(questionJSONData, "feedbackOnCorrect")); Index: lams_tool_scratchie/conf/language/lams/ApplicationResources.properties =================================================================== diff -u -raf79204a6effce72a9c276513762d4d7f7d5ae1a -rf0ff6bc30e8fa7e5d4201b7b9571194845ad3a83 --- lams_tool_scratchie/conf/language/lams/ApplicationResources.properties (.../ApplicationResources.properties) (revision af79204a6effce72a9c276513762d4d7f7d5ae1a) +++ lams_tool_scratchie/conf/language/lams/ApplicationResources.properties (.../ApplicationResources.properties) (revision f0ff6bc30e8fa7e5d4201b7b9571194845ad3a83) @@ -248,6 +248,7 @@ label.no.case.unimportant = No, case is unimportant label.yes.case.must.match = Yes, case must match label.case.sensitivity = Case sensitivity +label.exact.match = Learner answer must exactly match expected answer label.autocomplete.as.student = Autocomplete (as student types answer autocomplete with stemming from answers) label.general.feedback = General feedback label.authoring.choice.field.required = This field is required. Index: lams_tool_scratchie/src/java/org/lamsfoundation/lams/tool/scratchie/dao/hibernate/ScratchieSessionDAOHibernate.java =================================================================== diff -u -rb8e5c281efce81034ea2675a610ba3ea8faa41fb -rf0ff6bc30e8fa7e5d4201b7b9571194845ad3a83 --- lams_tool_scratchie/src/java/org/lamsfoundation/lams/tool/scratchie/dao/hibernate/ScratchieSessionDAOHibernate.java (.../ScratchieSessionDAOHibernate.java) (revision b8e5c281efce81034ea2675a610ba3ea8faa41fb) +++ lams_tool_scratchie/src/java/org/lamsfoundation/lams/tool/scratchie/dao/hibernate/ScratchieSessionDAOHibernate.java (.../ScratchieSessionDAOHibernate.java) (revision f0ff6bc30e8fa7e5d4201b7b9571194845ad3a83) @@ -33,12 +33,12 @@ import org.hibernate.query.Query; import org.lamsfoundation.lams.dao.hibernate.LAMSBaseDAO; import org.lamsfoundation.lams.learningdesign.ToolActivity; +import org.lamsfoundation.lams.qb.QbUtils; import org.lamsfoundation.lams.qb.model.QbToolQuestion; import org.lamsfoundation.lams.tool.scratchie.dao.ScratchieSessionDAO; import org.lamsfoundation.lams.tool.scratchie.model.ScratchieAnswerVisitLog; import org.lamsfoundation.lams.tool.scratchie.model.ScratchieItem; import org.lamsfoundation.lams.tool.scratchie.model.ScratchieSession; -import org.lamsfoundation.lams.tool.scratchie.service.IScratchieService; import org.lamsfoundation.lams.tool.scratchie.util.ScratchieSessionComparator; import org.lamsfoundation.lams.usermanagement.Organisation; import org.lamsfoundation.lams.usermanagement.OrganisationType; @@ -121,17 +121,18 @@ + (parentOrganisation == null ? "" : " OR l.organisation.organisationId = :parentOrganisationId OR " + "l.organisation.parentOrganisation.organisationId = :parentOrganisationId") - + ") AND item.qbQuestion.uid =:qbQuestionUid " - + "AND session.sessionId = visitLog.sessionId AND REGEXP_REPLACE(visitLog.answer, '" - + IScratchieService.VSA_ANSWER_NORMALISE_SQL_REG_EXP + "', '') = :answer"; + + ") AND item.qbQuestion.uid =:qbQuestionUid " + "AND session.sessionId = visitLog.sessionId AND " + + (qbToolQuestion.getQbQuestion().isExactMatch() ? "TRIM(visitLog.answer)" + : "REGEXP_REPLACE(visitLog.answer, '" + QbUtils.VSA_ANSWER_NORMALISE_SQL_REG_EXP + "', '')") + + " = :answer"; Query q = getSession().createQuery(FIND_BY_QBQUESTION_AND_FINISHED, Long.class); q.setParameter("qbQuestionUid", qbToolQuestion.getQbQuestion().getUid()); q.setParameter("organisationId", organisation.getOrganisationId()); if (parentOrganisation != null) { q.setParameter("parentOrganisationId", parentOrganisation.getOrganisationId()); } - String normalisedAnswer = answer.replaceAll(IScratchieService.VSA_ANSWER_NORMALISE_JAVA_REG_EXP, ""); + String normalisedAnswer = answer.replaceAll(QbUtils.VSA_ANSWER_NORMALISE_JAVA_REG_EXP, ""); q.setParameter("answer", normalisedAnswer); return q.list(); } Index: lams_tool_scratchie/src/java/org/lamsfoundation/lams/tool/scratchie/service/IScratchieService.java =================================================================== diff -u -red8e4fb944665c1f48832c59b95944c5b5875a78 -rf0ff6bc30e8fa7e5d4201b7b9571194845ad3a83 --- lams_tool_scratchie/src/java/org/lamsfoundation/lams/tool/scratchie/service/IScratchieService.java (.../IScratchieService.java) (revision ed8e4fb944665c1f48832c59b95944c5b5875a78) +++ lams_tool_scratchie/src/java/org/lamsfoundation/lams/tool/scratchie/service/IScratchieService.java (.../IScratchieService.java) (revision f0ff6bc30e8fa7e5d4201b7b9571194845ad3a83) @@ -56,9 +56,6 @@ */ public interface IScratchieService extends ICommonToolService { - public static final String VSA_ANSWER_NORMALISE_JAVA_REG_EXP = "\\W"; - public static final String VSA_ANSWER_NORMALISE_SQL_REG_EXP = "[^[:alpha:][:alnum:]_]"; - /** * Get Scratchie by toolContentID. * @@ -408,7 +405,8 @@ * @param oldItems * @param newItems */ - void recalculateUserAnswers(Scratchie scratchie, Set oldItems, Set newItems, String oldPresetMarks); + void recalculateUserAnswers(Scratchie scratchie, Set oldItems, Set newItems, + String oldPresetMarks); void releaseFromCache(Object object); Index: lams_tool_scratchie/src/java/org/lamsfoundation/lams/tool/scratchie/service/ScratchieServiceImpl.java =================================================================== diff -u -rb8e5c281efce81034ea2675a610ba3ea8faa41fb -rf0ff6bc30e8fa7e5d4201b7b9571194845ad3a83 --- lams_tool_scratchie/src/java/org/lamsfoundation/lams/tool/scratchie/service/ScratchieServiceImpl.java (.../ScratchieServiceImpl.java) (revision b8e5c281efce81034ea2675a610ba3ea8faa41fb) +++ lams_tool_scratchie/src/java/org/lamsfoundation/lams/tool/scratchie/service/ScratchieServiceImpl.java (.../ScratchieServiceImpl.java) (revision f0ff6bc30e8fa7e5d4201b7b9571194845ad3a83) @@ -629,7 +629,7 @@ List visitLogs = scratchieAnswerVisitDao.getVsaLogsByItem(item.getUid()); for (ScratchieAnswerVisitLog visitLog : visitLogs) { String answer = visitLog.getAnswer(); - if (QbUtils.normaliseVSAnswer(answer) == null) { + if (QbUtils.normaliseVSAnswer(answer, qbQuestion.isExactMatch()) == null) { continue; } @@ -1100,8 +1100,9 @@ String name = correctAnswersGroup.getName(); for (String userAnswer : userAnswers) { - String normalisedQuestionAnswer = QbUtils.normaliseVSAnswer(userAnswer); - if (QbUtils.isVSAnswerAllocated(name, normalisedQuestionAnswer, qbQuestion.isCaseSensitive())) { + String normalisedQuestionAnswer = QbUtils.normaliseVSAnswer(userAnswer, qbQuestion.isExactMatch()); + if (QbUtils.isVSAnswerAllocated(name, normalisedQuestionAnswer, qbQuestion.isCaseSensitive(), + qbQuestion.isExactMatch())) { return true; } } @@ -1145,9 +1146,10 @@ for (ScratchieAnswerVisitLog userLog : userLogs) { if (userLog.getQbToolQuestion().getUid().equals(item.getUid())) { itemAttempts++; - String normalisedQuestionAnswer = QbUtils.normaliseVSAnswer(userLog.getAnswer()); + String normalisedQuestionAnswer = QbUtils.normaliseVSAnswer(userLog.getAnswer(), + qbQuestion.isExactMatch()); if (correctVsaOption != null && QbUtils.isVSAnswerAllocated(correctVsaOption, normalisedQuestionAnswer, - qbQuestion.isCaseSensitive())) { + qbQuestion.isCaseSensitive(), qbQuestion.isExactMatch())) { break; } } Index: lams_tool_scratchie/src/java/org/lamsfoundation/lams/tool/scratchie/web/controller/AuthoringController.java =================================================================== diff -u -rf6247c953cc7bf9a17d4025ea8e8728ae55c11ed -rf0ff6bc30e8fa7e5d4201b7b9571194845ad3a83 --- lams_tool_scratchie/src/java/org/lamsfoundation/lams/tool/scratchie/web/controller/AuthoringController.java (.../AuthoringController.java) (revision f6247c953cc7bf9a17d4025ea8e8728ae55c11ed) +++ lams_tool_scratchie/src/java/org/lamsfoundation/lams/tool/scratchie/web/controller/AuthoringController.java (.../AuthoringController.java) (revision f0ff6bc30e8fa7e5d4201b7b9571194845ad3a83) @@ -380,6 +380,7 @@ if (!isMcqQuestionType) { form.setFeedback(qbQuestion.getFeedback()); form.setCaseSensitive(qbQuestion.isCaseSensitive()); + form.setExactMatch(qbQuestion.isExactMatch()); form.setAutocompleteEnabled(qbQuestion.isAutocompleteEnabled()); } @@ -531,6 +532,7 @@ if (!isMcqQuestionType) { qbQuestion.setFeedback(form.getFeedback()); qbQuestion.setCaseSensitive(form.isCaseSensitive()); + qbQuestion.setExactMatch(form.isExactMatch()); qbQuestion.setAutocompleteEnabled(form.isAutocompleteEnabled()); } Index: lams_tool_scratchie/web/pages/authoring/parts/addVsa.jsp =================================================================== diff -u -re423418cca5e77a3b54cb3be496b67abe01c4183 -rf0ff6bc30e8fa7e5d4201b7b9571194845ad3a83 --- lams_tool_scratchie/web/pages/authoring/parts/addVsa.jsp (.../addVsa.jsp) (revision e423418cca5e77a3b54cb3be496b67abe01c4183) +++ lams_tool_scratchie/web/pages/authoring/parts/addVsa.jsp (.../addVsa.jsp) (revision f0ff6bc30e8fa7e5d4201b7b9571194845ad3a83) @@ -144,17 +144,27 @@
- +
+ +
+ +
+
- +