From 4c317b1db545e23f86ca5fb3589be73a6fa8288e Mon Sep 17 00:00:00 2001
From: srosse <none@none>
Date: Fri, 4 Nov 2016 20:03:50 +0100
Subject: [PATCH] OO-2348: hotspot always visible, add shadow to the select
 state, add simple selenium test

---
 .../_content/hotspotInteraction.html          |   6 ++-
 .../static/js/jquery/qti/jquery.hotspot.js    |  40 +++++++++++++++---
 .../java/org/olat/selenium/ImsQTI21Test.java  |  35 +++++++++++++++
 .../org/olat/selenium/page/qti/QTI21Page.java |  15 +++++++
 .../page/repository/AuthoringEnvPage.java     |  14 ++++++
 .../file_resources/simple_QTI_21_hotspot.zip  | Bin 0 -> 9552 bytes
 6 files changed, 103 insertions(+), 7 deletions(-)
 create mode 100644 src/test/java/org/olat/test/file_resources/simple_QTI_21_hotspot.zip

diff --git a/src/main/java/org/olat/ims/qti21/ui/components/_content/hotspotInteraction.html b/src/main/java/org/olat/ims/qti21/ui/components/_content/hotspotInteraction.html
index 812a87d9af0..bb4aecb47da 100644
--- a/src/main/java/org/olat/ims/qti21/ui/components/_content/hotspotInteraction.html
+++ b/src/main/java/org/olat/ims/qti21/ui/components/_content/hotspotInteraction.html
@@ -25,8 +25,10 @@
 		jQuery(function() {
 			jQuery('#${qtiContainerId}_img').maphilight({
 				fillColor: '888888',
-				strokeColor: '0000ff',
-				strokeWidth: 3
+				strokeColor: '333333',
+				strokeOpacity: 0.5,
+				strokeWidth: 3,
+				alwaysOn: true
 			});
 
 			jQuery('#${qtiContainerId}').hotspotInteraction({
diff --git a/src/main/webapp/static/js/jquery/qti/jquery.hotspot.js b/src/main/webapp/static/js/jquery/qti/jquery.hotspot.js
index 83fc52d001a..26823d09e1a 100644
--- a/src/main/webapp/static/js/jquery/qti/jquery.hotspot.js
+++ b/src/main/webapp/static/js/jquery/qti/jquery.hotspot.js
@@ -29,7 +29,8 @@
     	for(i=areaIds.length; i-->0; ) {
     		var areaEl = jQuery('#ac_' + settings.responseIdentifier + '_' + areaIds[i]);
     		var data = areaEl.data('maphilight') || {};
-    		data.alwaysOn = true;
+    		data.selectedOn = true;
+    		colorData(data);
     		areaEl.data('maphilight', data).trigger('alwaysOn.maphilight');
     		
     		var inputElement = jQuery('<input type="hidden"/>')
@@ -51,13 +52,13 @@
     function clickHotspotArea(spot, containerId, responseIdentifier, maxChoices) {
     	var areaEl = jQuery(spot);
     	var data = areaEl.data('maphilight') || {};
-    	if(!data.alwaysOn) {
+    	if((typeof data.selectedOn === "undefined") || !data.selectedOn) {
     		var numOfChoices = maxChoices;
     		if(numOfChoices > 0) {
     			var countChoices = 0;
     			jQuery("area", "map[name='" + containerId + "_map']").each(function(index, el) {
     				var cData = jQuery(el).data('maphilight') || {};
-    				if(cData.alwaysOn) {
+    				if(cData.selectedOn) {
     					countChoices++;
     				}
     			});
@@ -66,7 +67,13 @@
     			}
     		}
     	}
-    	data.alwaysOn = !data.alwaysOn;
+    	
+    	if(typeof data.selectedOn === "undefined") {
+    		data.selectedOn = true;
+    	} else {
+    		data.selectedOn = !data.selectedOn;
+    	}
+    	colorData(data);
     	areaEl.data('maphilight', data).trigger('alwaysOn.maphilight');
 
     	var divContainer = jQuery('#' + containerId);
@@ -74,12 +81,35 @@
     	jQuery("area", "map[name='" + containerId + "_map']").each(function(index, el) {
     		var cAreaEl = jQuery(el);
     		var cData = cAreaEl.data('maphilight') || {};
-    		if(cData.alwaysOn) {
+    		if(cData.selectedOn) {
     			var inputElement = jQuery('<input type="hidden"/>')
     				.attr('name', 'qtiworks_response_' + responseIdentifier)
     				.attr('value', cAreaEl.data('qti-id'));
     			divContainer.append(inputElement);
     		}
     	});
+    };
+    
+    /*
+     * Color the data based on the selectedOn flag
+     */
+    function colorData(data) {
+    	if(data.selectedOn) {
+        	data.fillColor = '0000ff';
+    		data.strokeColor = '0000ff';
+    		data.strokeOpacity = 1;
+    		data.shadow = true;
+    		data.shadowX = 4;
+    		data.shadowY = 4;
+    		data.shadowRadius = 8;
+    		data.shadowColor = '000000';
+    		data.shadowOpacity = 0.8;
+    		data.shadowPosition = 'outside';
+    	} else {
+        	data.fillColor = '888888';
+    		data.strokeColor = '333333';
+    		data.strokeOpacity = 0.5;
+    		data.shadow = false;
+    	}
     }
 }( jQuery ));
diff --git a/src/test/java/org/olat/selenium/ImsQTI21Test.java b/src/test/java/org/olat/selenium/ImsQTI21Test.java
index 905e8104186..f13f466de13 100644
--- a/src/test/java/org/olat/selenium/ImsQTI21Test.java
+++ b/src/test/java/org/olat/selenium/ImsQTI21Test.java
@@ -131,7 +131,42 @@ public class ImsQTI21Test {
 			.closeTest()
 			.assertOnAttempts(1);
 		
+		//TODO continue
+	}
+	
+	/**
+	 * Check if the hotspot interaction send a "correct" feedback.
+	 * 
+	 * @param authorLoginPage
+	 * @throws IOException
+	 * @throws URISyntaxException
+	 */
+	@Test
+	@RunAsClient
+	public void qti21GraphicInteractionTest(@InitialPage LoginPage authorLoginPage)
+	throws IOException, URISyntaxException {
+		UserVO author = new UserRestClient(deploymentUrl).createAuthor();
+		authorLoginPage.loginAs(author.getLogin(), author.getPassword());
+		
+		//upload a test
+		String qtiTestTitle = "Simple QTI 2.1 " + UUID.randomUUID();
+		URL qtiTestUrl = JunitTestHelper.class.getResource("file_resources/simple_QTI_21_hotspot.zip");
+		File qtiTestFile = new File(qtiTestUrl.toURI());
+		navBar
+			.openAuthoringEnvironment()
+			.uploadResource(qtiTestTitle, qtiTestFile)
+			.clickToolbarRootCrumb();
+		
+		QTI21Page qtiPage = QTI21Page
+				.getQTI12Page(browser);
+		qtiPage
+			.answerHotspot("circle")
+			.saveAnswer()
+			.assertFeedback("Correct!")
+			.endTest()
+			.closeTest();
 		
+		//TODO check the results
 	}
 
 }
diff --git a/src/test/java/org/olat/selenium/page/qti/QTI21Page.java b/src/test/java/org/olat/selenium/page/qti/QTI21Page.java
index 2d162861fbe..b58b092dcd6 100644
--- a/src/test/java/org/olat/selenium/page/qti/QTI21Page.java
+++ b/src/test/java/org/olat/selenium/page/qti/QTI21Page.java
@@ -128,6 +128,13 @@ public class QTI21Page {
 		OOGraphene.waitBusy(browser);
 		return this;
 	}
+	
+	public QTI21Page answerHotspot(String shape) {
+		By areaBy = By.cssSelector("div.hotspotInteraction area[shape='" + shape + "']");
+		OOGraphene.waitElement(areaBy, 5, browser);
+		browser.findElement(areaBy).click();
+		return this;
+	}
 
 	//TODO still QTI 1.2
 	public QTI21Page answerKPrim(boolean... choices) {
@@ -166,6 +173,14 @@ public class QTI21Page {
 		return this;
 	}
 	
+	public QTI21Page assertFeedback(String feedback) {
+		By feedbackBy = By.xpath("//div[contains(@class,'modalFeedback')]/h4[contains(text(),'" + feedback + "')]");
+		OOGraphene.waitElement(feedbackBy, 5, browser);
+		List<WebElement> feedbackEls = browser.findElements(feedbackBy);
+		Assert.assertEquals(1, feedbackEls.size());
+		return this;
+	}
+	
 	public QTI21Page endTest() {
 		By endBy = By.cssSelector("a.o_sel_end_testpart");
 		browser.findElement(endBy).click();
diff --git a/src/test/java/org/olat/selenium/page/repository/AuthoringEnvPage.java b/src/test/java/org/olat/selenium/page/repository/AuthoringEnvPage.java
index 253c195742c..340059ed5d7 100644
--- a/src/test/java/org/olat/selenium/page/repository/AuthoringEnvPage.java
+++ b/src/test/java/org/olat/selenium/page/repository/AuthoringEnvPage.java
@@ -22,6 +22,7 @@ package org.olat.selenium.page.repository;
 import java.io.File;
 
 import org.junit.Assert;
+import org.olat.selenium.page.course.CoursePageFragment;
 import org.olat.selenium.page.course.CourseWizardPage;
 import org.olat.selenium.page.graphene.OOGraphene;
 import org.openqa.selenium.By;
@@ -196,6 +197,19 @@ public class AuthoringEnvPage {
 		OOGraphene.waitBusy(browser);
 	}
 	
+	/**
+	 * Click back from the editor
+	 * 
+	 * @return
+	 */
+	public CoursePageFragment clickToolbarRootCrumb() {
+		OOGraphene.closeBlueMessageWindow(browser);
+		By toolbarBackBy = By.xpath("//li[contains(@class,'o_breadcrumb_back')]/following-sibling::li/a");
+		browser.findElement(toolbarBackBy).click();
+		OOGraphene.waitBusy(browser);
+		return new CoursePageFragment(browser);
+	}
+	
 	public enum ResourceType {
 		course("CourseModule"),
 		cp("FileResource.IMSCP"),
diff --git a/src/test/java/org/olat/test/file_resources/simple_QTI_21_hotspot.zip b/src/test/java/org/olat/test/file_resources/simple_QTI_21_hotspot.zip
new file mode 100644
index 0000000000000000000000000000000000000000..ba1f401bdf5bc3980e7f203340674fe2bf75f12c
GIT binary patch
literal 9552
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

literal 0
HcmV?d00001

-- 
GitLab