diff --git a/src/main/java/org/olat/modules/qpool/ui/metadata/QuestionMetadataEditController.java b/src/main/java/org/olat/modules/qpool/ui/metadata/QuestionMetadataEditController.java index 9c1f2f39084d3d787765258abec1fe7111167f47..cc6c8b0a1a55deef7ac4b97966188e4100528491 100644 --- a/src/main/java/org/olat/modules/qpool/ui/metadata/QuestionMetadataEditController.java +++ b/src/main/java/org/olat/modules/qpool/ui/metadata/QuestionMetadataEditController.java @@ -60,7 +60,6 @@ import org.springframework.beans.factory.annotation.Autowired; */ public class QuestionMetadataEditController extends FormBasicController { - private StaticTextElement typeEl; private IntegerElement learningTimeDayElement; private IntegerElement learningTimeHourElement; private IntegerElement learningTimeMinuteElement; @@ -91,7 +90,7 @@ public class QuestionMetadataEditController extends FormBasicController { @Override protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { - typeEl = uifactory.addStaticTextElement("question.type", "", formLayout); + StaticTextElement typeEl = uifactory.addStaticTextElement("question.type", "", formLayout); QItemType type = item.getType(); if(type == null || type.getType() == null) { typeEl.setValue(""); @@ -112,49 +111,59 @@ public class QuestionMetadataEditController extends FormBasicController { LOMDuration duration = MetadataConverterHelper.convertDuration(item.getEducationalLearningTime()); learningTimeDayElement = uifactory.addIntegerElement("learningTime.day", "", duration.getDay(), learningTimeContainer); + learningTimeDayElement.setElementCssClass("o_sel_learning_time_d"); ((AbstractComponent)learningTimeDayElement.getComponent()).setDomReplacementWrapperRequired(false); learningTimeDayElement.setDisplaySize(3); learningTimeDayElement.setMandatory(true); learningTimeHourElement = uifactory.addIntegerElement("learningTime.hour", "", duration.getHour(), learningTimeContainer); ((AbstractComponent)learningTimeHourElement.getComponent()).setDomReplacementWrapperRequired(false); + learningTimeHourElement.setElementCssClass("o_sel_learning_time_H"); learningTimeHourElement.setDisplaySize(3); learningTimeHourElement.setMandatory(true); learningTimeMinuteElement = uifactory.addIntegerElement("learningTime.minute", "", duration.getMinute(), learningTimeContainer); ((AbstractComponent)learningTimeMinuteElement.getComponent()).setDomReplacementWrapperRequired(false); + learningTimeMinuteElement.setElementCssClass("o_sel_learning_time_m"); learningTimeMinuteElement.setDisplaySize(3); learningTimeMinuteElement.setMandatory(true); learningTimeSecondElement = uifactory.addIntegerElement("learningTime.second", "", duration.getSeconds(), learningTimeContainer); ((AbstractComponent)learningTimeSecondElement.getComponent()).setDomReplacementWrapperRequired(false); + learningTimeSecondElement.setElementCssClass("o_sel_learning_time_s"); learningTimeSecondElement.setDisplaySize(3); learningTimeSecondElement.setMandatory(true); String difficulty = bigDToString(item.getDifficulty()); difficultyEl = uifactory.addTextElement("question.difficulty", "question.difficulty", 24, difficulty, formLayout); + difficultyEl.setElementCssClass("o_sel_difficulty"); difficultyEl.setExampleKey("question.difficulty.example", null); difficultyEl.setDisplaySize(4); String stdevDifficulty = bigDToString(item.getStdevDifficulty()); stdevDifficultyEl = uifactory.addTextElement("question.stdevDifficulty", "question.stdevDifficulty", 24, stdevDifficulty, formLayout); + stdevDifficultyEl.setElementCssClass("o_sel_std_dev_difficulty"); stdevDifficultyEl.setExampleKey("question.stdevDifficulty.example", null); stdevDifficultyEl.setDisplaySize(4); String differentiation = bigDToString(item.getDifferentiation()); differentiationEl = uifactory.addTextElement("question.differentiation", "question.differentiation", 24, differentiation, formLayout); differentiationEl.setExampleKey("question.differentiation.example", null); + differentiationEl.setElementCssClass("o_sel_std_differentation"); differentiationEl.setDisplaySize(4); String numAnswerAlt = item.getNumOfAnswerAlternatives() < 0 ? "" : Integer.toString(item.getNumOfAnswerAlternatives()); numAnswerAltEl = uifactory.addTextElement("question.numOfAnswerAlternatives", "question.numOfAnswerAlternatives", 24, numAnswerAlt, formLayout); + numAnswerAltEl.setElementCssClass("o_sel_distractors"); numAnswerAltEl.setDisplaySize(4); String numUsage = item.getUsage() < 0 ? "" : Integer.toString(item.getUsage()); usageEl = uifactory.addTextElement("question.usage", "question.usage", 24, numUsage, formLayout); + usageEl.setElementCssClass("o_sel_usage"); usageEl.setDisplaySize(4); buttonsCont = FormLayoutContainer.createButtonLayout("buttons", getTranslator()); + buttonsCont.setElementCssClass("o_sel_qpool_metadata_buttons"); buttonsCont.setRootForm(mainForm); formLayout.add(buttonsCont); uifactory.addFormSubmitButton("ok", "ok", buttonsCont); diff --git a/src/main/java/org/olat/modules/qpool/ui/metadata/_content/item_metadatas.html b/src/main/java/org/olat/modules/qpool/ui/metadata/_content/item_metadatas.html index 684084465a8352fa9995578cb3715cc7cf267200..d794cd318c15388b8fff2f8c0593ed074421cc30 100644 --- a/src/main/java/org/olat/modules/qpool/ui/metadata/_content/item_metadatas.html +++ b/src/main/java/org/olat/modules/qpool/ui/metadata/_content/item_metadatas.html @@ -3,9 +3,7 @@ <div class="panel-heading"> <h4 class="panel-title"> <i id="collapseGeneralToggler" class="o_icon o_icon-fw #if($inGeneral) o_icon_close_togglebox #else o_icon_open_togglebox #end"> </i> - <a data-toggle="collapse" data-parent="#accordion" href="#general"> - $r.translate("general") - </a> + <a data-toggle="collapse" data-parent="#accordion" href="#general">$r.translate("general")</a> </h4> </div> <div id="general" class="panel-collapse collapse $!inGeneral"> @@ -23,13 +21,11 @@ }) </script> </div> - <div class="panel panel-default"> + <div class="panel panel-default o_sel_qpool_metadata_item_analyse"> <div class="panel-heading"> <h4 class="panel-title"> <i id="collapseQuestionToggler" class="o_icon o_icon-fw #if($inQuestion) o_icon_close_togglebox #else o_icon_open_togglebox #end"> </i> - <a data-toggle="collapse" data-parent="#accordion" href="#question"> - $r.translate("question") - </a> + <a data-toggle="collapse" data-parent="#accordion" href="#question">$r.translate("question")</a> </h4> </div> <div id="question" class="panel-collapse collapse $!inQuestion"> @@ -38,15 +34,13 @@ </div> </div> <script> - /* <![CDATA[ */ - jQuery('#question').on('hide.bs.collapse', function () { - jQuery('#collapseQuestionToggler').removeClass('o_icon_close_togglebox').addClass('o_icon_open_togglebox'); - }) - jQuery('#question').on('show.bs.collapse', function () { - jQuery('#collapseQuestionToggler').removeClass('o_icon_open_togglebox').addClass('o_icon_close_togglebox'); - $r.backgroundCommand("show","panel","question") - }) - /* ]]> */ + jQuery('#question').on('hide.bs.collapse', function () { + jQuery('#collapseQuestionToggler').removeClass('o_icon_close_togglebox').addClass('o_icon_open_togglebox'); + }) + jQuery('#question').on('show.bs.collapse', function () { + jQuery('#collapseQuestionToggler').removeClass('o_icon_open_togglebox').addClass('o_icon_close_togglebox'); + $r.backgroundCommand("show","panel","question") + }) </script> </div> <div class="panel panel-default"> diff --git a/src/test/java/org/olat/selenium/QuestionPoolTest.java b/src/test/java/org/olat/selenium/QuestionPoolTest.java index a42e869a7f518a3ab04f64ae588d33819966a6f8..d190bff7867c6f6b342c0f420da49c792bdef7d1 100644 --- a/src/test/java/org/olat/selenium/QuestionPoolTest.java +++ b/src/test/java/org/olat/selenium/QuestionPoolTest.java @@ -230,6 +230,7 @@ public class QuestionPoolTest extends Deployments { "Interessant", "Add. infos", "Wide coverage", "formative") .saveGeneralMetadata(); + // open quick view questionPool .clickToolbarBack() .assertQuestionInList(questionTitle, QTI21QuestionType.mc.name()) @@ -243,8 +244,55 @@ public class QuestionPoolTest extends Deployments { .assertAdditionalInfos("Add. infos") .assertCoverage("Wide coverage") .assertAssessmentType("formative"); + } + + /** + * An author create a QTI 2.1 question, a fill in blank, + * and fill the item analyze metadata. Go back in list and check + * that the metadata are there. + * + * @param loginPage + * @throws IOException + * @throws URISyntaxException + */ + @Test + @RunAsClient + public void questionPoolItemAnalyseMetadata() + throws IOException, URISyntaxException { + // The author create a new question with metadata + UserVO author = new UserRestClient(deploymentUrl).createAuthor("Lili"); + + LoginPage loginPage = LoginPage.load(browser, deploymentUrl); + loginPage + .loginAs(author.getLogin(), author.getPassword()) + .resume(); + + String questionTitle = "MetaMC-" + UUID.randomUUID(); + NavigationPage navBar = NavigationPage.load(browser); + QuestionPoolPage questionPool = navBar.assertOnNavigationPage() + .openQuestionPool(); + questionPool + .selectMyQuestions() + .newQuestion(questionTitle, QTI21QuestionType.fib) + .metadata() + .openItemAnalyse() + .setLearningTime(1, 5, 3, 35) + .setItemAnalyse(0.5d, 0.3d, -0.7d, 2, 3) + .saveItemAnalyse(); // open quick view + questionPool + .clickToolbarBack() + .assertQuestionInList(questionTitle, QTI21QuestionType.fib.name()) + .openQuickView(questionTitle) + .metadata() + .openItemAnalyse() + .assertLearningTime(1, 5, 3, 35) + .assertDifficulty(0.5d) + .assertStandardDeviation(0.3d) + .assertDiscriminationIndex(-0.7d) + .assertDistractors(2) + .assertUsage(3); } } diff --git a/src/test/java/org/olat/selenium/page/qpool/QuestionMetadataPage.java b/src/test/java/org/olat/selenium/page/qpool/QuestionMetadataPage.java index a4afd85f38e991fefce27ad5a040ac13611e49af..48831ae9ef3003f6ab90f677d6187f51db99fe06 100644 --- a/src/test/java/org/olat/selenium/page/qpool/QuestionMetadataPage.java +++ b/src/test/java/org/olat/selenium/page/qpool/QuestionMetadataPage.java @@ -22,6 +22,7 @@ package org.olat.selenium.page.qpool; import org.olat.selenium.page.graphene.OOGraphene; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; import org.openqa.selenium.support.ui.Select; /** @@ -43,14 +44,21 @@ public class QuestionMetadataPage { } public QuestionMetadataPage openGeneral() { - By hrefBy = By.cssSelector("div.o_sel_qpool_metadata_general>div>h4>a"); + return openMetadata("o_sel_qpool_metadata_general"); + } + + public QuestionMetadataPage openItemAnalyse() { + return openMetadata("o_sel_qpool_metadata_item_analyse"); + } + + private QuestionMetadataPage openMetadata(String panelClass) { + By hrefBy = By.cssSelector("div." + panelClass + ">div>h4>a"); OOGraphene.waitElement(hrefBy, browser); browser.findElement(hrefBy).click(); OOGraphene.waitingALittleLonger();// wait the accordion opens up - By generalMetadata = By.cssSelector("div.o_sel_qpool_metadata_general div.panel-body fieldset.o_form"); + By generalMetadata = By.cssSelector("div." + panelClass + " div.panel-body fieldset.o_form"); OOGraphene.waitElement(generalMetadata, browser); - return this; } @@ -93,6 +101,74 @@ public class QuestionMetadataPage { return this; } + public QuestionMetadataPage setLearningTime(Integer days, Integer hours, Integer minutes, Integer seconds) { + + if(days != null) { + By dayBy = By.cssSelector("div.o_sel_qpool_metadata_item_analyse input.o_sel_learning_time_d[type='text']"); + WebElement dayEl = browser.findElement(dayBy); + dayEl.clear(); + dayEl.sendKeys(days.toString()); + } + if(hours != null) { + By hourBy = By.cssSelector("div.o_sel_qpool_metadata_item_analyse input.o_sel_learning_time_H[type='text']"); + WebElement hourEl = browser.findElement(hourBy); + hourEl.clear(); + hourEl.sendKeys(hours.toString()); + } + if(minutes != null) { + By minuteBy = By.cssSelector("div.o_sel_qpool_metadata_item_analyse input.o_sel_learning_time_m[type='text']"); + WebElement minuteEl = browser.findElement(minuteBy); + minuteEl.clear(); + minuteEl.sendKeys(minutes.toString()); + } + if(seconds != null) { + By secondBy = By.cssSelector("div.o_sel_qpool_metadata_item_analyse input.o_sel_learning_time_s[type='text']"); + WebElement secondEl = browser.findElement(secondBy); + secondEl.clear(); + secondEl.sendKeys(seconds.toString()); + } + return this; + } + + /** + * + * @param difficulty Value between 0.0 and 1.0 + * @param standardDeviation Value between 0.0 and 1.0 + * @param discriminationIndex Value between -1.0 and 1.0 + * @param distractors The number of distractors + * @param usage + * @return Itself + */ + public QuestionMetadataPage setItemAnalyse(Double difficulty, Double standardDeviation, + Double discriminationIndex, Integer distractors, Integer usage) { + + if(difficulty != null) { + By difficultyBy = By.cssSelector(".o_sel_qpool_metadata_item_analyse .o_sel_difficulty input[type='text']"); + browser.findElement(difficultyBy).sendKeys(difficulty.toString()); + } + if(standardDeviation != null) { + By deviationBy = By.cssSelector(".o_sel_qpool_metadata_item_analyse .o_sel_std_dev_difficulty input[type='text']"); + browser.findElement(deviationBy).sendKeys(standardDeviation.toString()); + } + if(discriminationIndex != null) { + By discriminationBy = By.cssSelector(".o_sel_qpool_metadata_item_analyse .o_sel_std_differentation input[type='text']"); + browser.findElement(discriminationBy).sendKeys(discriminationIndex.toString()); + } + if(distractors != null) { + By distractorsBy = By.cssSelector(".o_sel_qpool_metadata_item_analyse .o_sel_distractors input[type='text']"); + WebElement distractorsEl = browser.findElement(distractorsBy); + distractorsEl.clear(); + distractorsEl.sendKeys(distractors.toString()); + } + if(usage != null) { + By usageBy = By.cssSelector(".o_sel_qpool_metadata_item_analyse .o_sel_usage input[type='text']"); + WebElement usageEl = browser.findElement(usageBy); + usageEl.clear(); + usageEl.sendKeys(usage.toString()); + } + return this; + } + public QuestionMetadataPage assertTopic(String topic) { By topicBy = By.xpath("//div[contains(@class,'o_sel_qpool_metadata_topic')]//input[@value='" + topic + "']"); OOGraphene.waitElement(topicBy, browser); @@ -135,11 +211,69 @@ public class QuestionMetadataPage { return this; } + public QuestionMetadataPage assertLearningTime(Integer days, Integer hours, Integer minutes, Integer seconds) { + if(days != null) { + By dayBy = By.xpath("//div[contains(@class,'o_sel_qpool_metadata_item_analyse')]//input[@value='" + days + "'][contains(@class,'o_sel_learning_time_d')]"); + OOGraphene.waitElement(dayBy, browser); + } + if(hours != null) { + By hourBy = By.xpath("//div[contains(@class,'o_sel_qpool_metadata_item_analyse')]//input[@value='" + hours + "'][contains(@class,'o_sel_learning_time_H')]"); + OOGraphene.waitElement(hourBy, browser); + } + if(minutes != null) { + By minuteBy = By.xpath("//div[contains(@class,'o_sel_qpool_metadata_item_analyse')]//input[@value='" + minutes + "'][contains(@class,'o_sel_learning_time_m')]"); + OOGraphene.waitElement(minuteBy, browser); + } + if(seconds != null) { + By secondBy = By.xpath("//div[contains(@class,'o_sel_qpool_metadata_item_analyse')]//input[@value='" + seconds + "'][contains(@class,'o_sel_learning_time_s')]"); + OOGraphene.waitElement(secondBy, browser); + } + return this; + } + + public QuestionMetadataPage assertDifficulty(Double diffculty) { + By difficultyBy = By.xpath("//div[contains(@class,'o_sel_difficulty')]//input[@value='" + diffculty + "']"); + OOGraphene.waitElement(difficultyBy, browser); + return this; + } + + public QuestionMetadataPage assertDiscriminationIndex(Double discriminationIndex) { + By discriminationIndexBy = By.xpath("//div[contains(@class,'o_sel_std_differentation')]//input[@value='" + discriminationIndex + "']"); + OOGraphene.waitElement(discriminationIndexBy, browser); + return this; + } + + public QuestionMetadataPage assertStandardDeviation(Double stdDeviation) { + By deviationBy = By.xpath("//div[contains(@class,'o_sel_std_dev_difficulty')]//input[@value='" + stdDeviation + "']"); + OOGraphene.waitElement(deviationBy, browser); + return this; + } + + public QuestionMetadataPage assertDistractors(Integer distractors) { + By distractorsBy = By.xpath("//div[contains(@class,'o_sel_distractors')]//input[@value='" + distractors + "']"); + OOGraphene.waitElement(distractorsBy, browser); + return this; + } + + public QuestionMetadataPage assertUsage(Integer usage) { + By usageBy = By.xpath("//div[contains(@class,'o_sel_usage')]//input[@value='" + usage + "']"); + OOGraphene.waitElement(usageBy, browser); + return this; + } + public QuestionMetadataPage saveGeneralMetadata() { - By buttonsBy = By.cssSelector("div.o_sel_qpool_metadata_general div.panel-body div.o_sel_qpool_metadata_buttons"); + return saveMetadata("o_sel_qpool_metadata_general"); + } + + public QuestionMetadataPage saveItemAnalyse() { + return saveMetadata("o_sel_qpool_metadata_item_analyse"); + } + + private QuestionMetadataPage saveMetadata(String panelClass) { + By buttonsBy = By.cssSelector("div." + panelClass + " div.panel-body div.o_sel_qpool_metadata_buttons"); OOGraphene.moveTo(buttonsBy, browser); - By saveBy = By.cssSelector("div.o_sel_qpool_metadata_general div.panel-body div.o_sel_qpool_metadata_buttons button.btn.btn-primary"); + By saveBy = By.cssSelector("div." + panelClass + " div.panel-body div.o_sel_qpool_metadata_buttons button.btn.btn-primary"); browser.findElement(saveBy).click(); OOGraphene.waitBusy(browser); OOGraphene.moveTop(browser);