Skip to content
Snippets Groups Projects
Commit 221508a1 authored by srosse's avatar srosse
Browse files

OO-2978: implements 4 more color choices for the hotspots

parent e4e32821
No related branches found
No related tags found
No related merge requests found
...@@ -146,6 +146,25 @@ public class QTI21Constants { ...@@ -146,6 +146,25 @@ public class QTI21Constants {
public static final String CSS_MATCH_SOURCE_BOTTOM = "source-bottom"; public static final String CSS_MATCH_SOURCE_BOTTOM = "source-bottom";
public static final String CSS_HOTSPOT_DISABLE_SHADOW = "hotspot-noshadow";
public enum HotspotLayouts {
standard(""),
light("hotspot-light"),
inverted("hotspot-inverted"),
green("hotspot-green"),
purple("hotspot-purple");
private final String cssClass;
private HotspotLayouts(String cssClass) {
this.cssClass = cssClass;
}
public String cssClass() {
return cssClass;
}
}
} }
\ No newline at end of file
...@@ -29,12 +29,14 @@ import static org.olat.ims.qti21.model.xml.QtiNodesExtractor.extractIdentifiersF ...@@ -29,12 +29,14 @@ import static org.olat.ims.qti21.model.xml.QtiNodesExtractor.extractIdentifiersF
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamResult;
import org.olat.core.gui.render.StringOutput; import org.olat.core.gui.render.StringOutput;
import org.olat.core.util.StringHelper;
import org.olat.ims.qti21.QTI21Constants; import org.olat.ims.qti21.QTI21Constants;
import org.olat.ims.qti21.model.IdentifierGenerator; import org.olat.ims.qti21.model.IdentifierGenerator;
import org.olat.ims.qti21.model.QTI21QuestionType; import org.olat.ims.qti21.model.QTI21QuestionType;
...@@ -223,6 +225,32 @@ public class HotspotAssessmentItemBuilder extends AssessmentItemBuilder { ...@@ -223,6 +225,32 @@ public class HotspotAssessmentItemBuilder extends AssessmentItemBuilder {
} }
} }
public boolean hasHotspotInteractionClass(String cssClass) {
List<String> cssClassses = hotspotInteraction.getClassAttr();
return cssClassses != null && cssClassses.contains(cssClass);
}
public void addHotspotInteractionClass(String cssClass) {
if(!StringHelper.containsNonWhitespace(cssClass)) return;
List<String> cssClassses = hotspotInteraction.getClassAttr();
cssClassses = cssClassses == null ? new ArrayList<>() : new ArrayList<>(cssClassses);
cssClassses.add(cssClass);
hotspotInteraction.setClassAttr(cssClassses);
}
public void removeHotspotInteractionClass(String cssClass) {
if(cssClass == null || hotspotInteraction.getClassAttr() == null) return;
List<String> cssClassList = new ArrayList<>(hotspotInteraction.getClassAttr());
for(Iterator<String> cssClassIt= cssClassList.iterator(); cssClassIt.hasNext(); ) {
if(cssClass.equals(cssClassIt.next())) {
cssClassIt.remove();
}
}
hotspotInteraction.setClassAttr(cssClassList);
}
public boolean isCorrect(HotspotChoice choice) { public boolean isCorrect(HotspotChoice choice) {
if(correctAnswers == null) { if(correctAnswers == null) {
correctAnswers = new ArrayList<>(); correctAnswers = new ArrayList<>();
......
...@@ -24,15 +24,83 @@ ...@@ -24,15 +24,83 @@
</map> </map>
</div> </div>
<script type="text/javascript"> <script type="text/javascript">
jQuery(function() { /* <![CDATA[ */
jQuery('#${qtiContainerId}_img').maphilight({ var maphilightSettings;
#if($r.hasCssClass($interaction, "hotspot-light"))
maphilightSettings = {
fillColor: 'dddddd',
fillOpacity: 0,
strokeColor: '7E7E7E',
strokeOpacity: 1.0,
selectedFillColor: '337ab7',
selectedFillOpacity: 0.05,
selectedStrokeColor: '337ab7',
selectedStrokeOpacity: 1.0
};
#elseif($r.hasCssClass($interaction, "hotspot-inverted"))
maphilightSettings = {
fillColor: '6E6E6E',//'bbbbbb',
fillOpacity: 0.5,// 0.5,
strokeColor: '3E3E3E', //'666666',
strokeOpacity: 1.0,//0.8,
selectedFillColor: 'DEDEDE',
selectedFillOpacity: 0.2,
selectedStrokeColor: 'CECECE',
selectedStrokeOpacity: 1
};
#elseif($r.hasCssClass($interaction, "hotspot-green"))
maphilightSettings = {
fillColor: '8E8E8E',
fillOpacity: 0.25,
strokeColor: 'CECECE',//'fd98c9',
strokeOpacity: 0.8,
selectedFillColor: '86c351',
selectedFillOpacity: 0.5,
selectedStrokeColor: '518b33',
selectedStrokeOpacity: 1.0
};
#elseif($r.hasCssClass($interaction, "hotspot-purple"))
maphilightSettings = {
fillColor: '8E8E8E',
fillOpacity: 0.33,
strokeColor: 'CECECE',//'fd98c9',
strokeOpacity: 1.0,
selectedFillColor: 'eaa8ff',
selectedFillOpacity: 0.5,
selectedStrokeColor: 'ab47cb',
selectedStrokeOpacity: 1.0
};
#else
maphilightSettings = {
fillColor: 'bbbbbb', fillColor: 'bbbbbb',
fillOpacity: 0.5, fillOpacity: 0.5,
strokeColor: '666666', strokeColor: '6E6E6E',
strokeOpacity: 0.8, strokeOpacity: 1.0,
strokeWidth: 3,
alwaysOn: true selectedFillColor: '0000ff',
}); selectedFillOpacity: 0.5,
selectedStrokeColor: '0000ff',
selectedStrokeOpacity: 1.0
};
#end
#if($r.hasCssClass($interaction, "hotspot-noshadow"))
maphilightSettings.selectedShadow = false;
#else
maphilightSettings.selectedShadow = true;
#end
jQuery(function() {
maphilightSettings.strokeWidth = 3;
maphilightSettings.alwaysOn = true;
jQuery('#${qtiContainerId}_img').maphilight(maphilightSettings);
jQuery('#${qtiContainerId}').hotspotInteraction({ jQuery('#${qtiContainerId}').hotspotInteraction({
responseIdentifier: '$responseIdentifier', responseIdentifier: '$responseIdentifier',
...@@ -40,8 +108,10 @@ ...@@ -40,8 +108,10 @@
maxChoices: $interaction.maxChoices, maxChoices: $interaction.maxChoices,
singleChoice: $singleChoice, singleChoice: $singleChoice,
responseValue: '$r.toString($responseValue,",")', responseValue: '$r.toString($responseValue,",")',
opened: $isItemSessionOpen opened: $isItemSessionOpen,
maphilightSettings: maphilightSettings
}); });
}); });
/* ]]> */
</script> </script>
</div> </div>
...@@ -138,6 +138,13 @@ item.session.control.attempts.hint=Diese Einschr\u00E4nkung der L\u00F6sungsvers ...@@ -138,6 +138,13 @@ item.session.control.attempts.hint=Diese Einschr\u00E4nkung der L\u00F6sungsvers
item.session.control.show.solution=L\u00F6sung anzeigen item.session.control.show.solution=L\u00F6sung anzeigen
item.session.control.show.solution.hint=Beim R\u00FCckblick werden auch L\u00F6sungen angezeigt. item.session.control.show.solution.hint=Beim R\u00FCckblick werden auch L\u00F6sungen angezeigt.
hour.short=h hour.short=h
hotspot.layout=Darstellung
hotspot.layout.standard=Standard blau
hotspot.layout.inverted=Invertiert
hotspot.layout.light=Hell
hotspot.layout.green=Gr\u00FCn
hotspot.layout.purple=Violett
hotspot.layout.shadow=Shatten wenn ausgewhlt
minute.short=m minute.short=m
MULTIPLE=Multiple choice MULTIPLE=Multiple choice
max.score=Maximal erreichbare Punktzahl max.score=Maximal erreichbare Punktzahl
......
...@@ -126,6 +126,13 @@ form.testPart.navigationMode.linear=Linear ...@@ -126,6 +126,13 @@ form.testPart.navigationMode.linear=Linear
form.testPart.navigationMode.nonlinear=Non linear form.testPart.navigationMode.nonlinear=Non linear
form.unkown=Unkown form.unkown=Unkown
form.upload=File upload form.upload=File upload
hotspot.layout=Layout
hotspot.layout.standard=Standard blue
hotspot.layout.inverted=Inverted
hotspot.layout.light=Hell
hotspot.layout.green=Green
hotspot.layout.purple=Purple
hotspot.layout.shadow=Shadow if selected
hour.short=h hour.short=h
minute.short=m minute.short=m
inherit=Inherit inherit=Inherit
......
...@@ -58,6 +58,8 @@ import org.olat.core.util.ValidationStatus; ...@@ -58,6 +58,8 @@ import org.olat.core.util.ValidationStatus;
import org.olat.core.util.WebappHelper; import org.olat.core.util.WebappHelper;
import org.olat.core.util.vfs.LocalFileImpl; import org.olat.core.util.vfs.LocalFileImpl;
import org.olat.core.util.vfs.VFSContainer; import org.olat.core.util.vfs.VFSContainer;
import org.olat.ims.qti21.QTI21Constants;
import org.olat.ims.qti21.QTI21Constants.HotspotLayouts;
import org.olat.ims.qti21.model.IdentifierGenerator; import org.olat.ims.qti21.model.IdentifierGenerator;
import org.olat.ims.qti21.model.QTI21QuestionType; import org.olat.ims.qti21.model.QTI21QuestionType;
import org.olat.ims.qti21.model.xml.interactions.HotspotAssessmentItemBuilder; import org.olat.ims.qti21.model.xml.interactions.HotspotAssessmentItemBuilder;
...@@ -78,6 +80,7 @@ import uk.ac.ed.ph.jqtiplus.value.Cardinality; ...@@ -78,6 +80,7 @@ import uk.ac.ed.ph.jqtiplus.value.Cardinality;
*/ */
public class HotspotEditorController extends FormBasicController { public class HotspotEditorController extends FormBasicController {
private static final String[] onKeys = new String[] { "on" };
private static final Set<String> mimeTypes = new HashSet<>(); private static final Set<String> mimeTypes = new HashSet<>();
static { static {
mimeTypes.add("image/gif"); mimeTypes.add("image/gif");
...@@ -93,6 +96,9 @@ public class HotspotEditorController extends FormBasicController { ...@@ -93,6 +96,9 @@ public class HotspotEditorController extends FormBasicController {
private FormLayoutContainer hotspotsCont; private FormLayoutContainer hotspotsCont;
private FormLink newCircleButton, newRectButton; private FormLink newCircleButton, newRectButton;
private MultipleSelectionElement correctHotspotsEl; private MultipleSelectionElement correctHotspotsEl;
private SingleSelection layoutEl;
private MultipleSelectionElement shadowEl;
private final boolean restrictedEdit; private final boolean restrictedEdit;
private final HotspotAssessmentItemBuilder itemBuilder; private final HotspotAssessmentItemBuilder itemBuilder;
...@@ -185,6 +191,31 @@ public class HotspotEditorController extends FormBasicController { ...@@ -185,6 +191,31 @@ public class HotspotEditorController extends FormBasicController {
correctHotspotsEl.setEnabled(!restrictedEdit); correctHotspotsEl.setEnabled(!restrictedEdit);
correctHotspotsEl.addActionListener(FormEvent.ONCHANGE); correctHotspotsEl.addActionListener(FormEvent.ONCHANGE);
rebuildWrappersAndCorrectSelection(); rebuildWrappersAndCorrectSelection();
HotspotLayouts[] layouts = HotspotLayouts.values();
String[] layoutKeys = new String[layouts.length];
String[] layoutValues = new String[layouts.length];
for(int i=layouts.length; i-->0; ) {
layoutKeys[i] = layouts[i].cssClass();
layoutValues[i] = translate("hotspot.layout." + layouts[i].name());
}
layoutEl = uifactory.addDropdownSingleselect("hotspot.layout", "hotspot.layout", formLayout, layoutKeys, layoutValues, null);
boolean found = false;
for(int i=layoutKeys.length; i-->0; ) {
if(itemBuilder.hasHotspotInteractionClass(layoutKeys[i])) {
layoutEl.select(layoutKeys[i], true);
found = true;
}
}
if(!found) {
layoutEl.select(layoutKeys[0], true);
}
shadowEl = uifactory.addCheckboxesHorizontal("hotspot.layout.shadow", "hotspot.layout.shadow", formLayout,
onKeys, new String[] { "" });
if(!itemBuilder.hasHotspotInteractionClass(QTI21Constants.CSS_HOTSPOT_DISABLE_SHADOW)) {
shadowEl.select(onKeys[0], true);
}
// Submit Button // Submit Button
FormLayoutContainer buttonsContainer = FormLayoutContainer.createButtonLayout("buttons", getTranslator()); FormLayoutContainer buttonsContainer = FormLayoutContainer.createButtonLayout("buttons", getTranslator());
...@@ -424,6 +455,20 @@ public class HotspotEditorController extends FormBasicController { ...@@ -424,6 +455,20 @@ public class HotspotEditorController extends FormBasicController {
} }
updateHotspots(ureq); updateHotspots(ureq);
if(layoutEl.isOneSelected()) {
String selectedLayout = layoutEl.getSelectedKey();
for(HotspotLayouts layout:HotspotLayouts.values()) {
itemBuilder.removeHotspotInteractionClass(layout.cssClass());
}
itemBuilder.addHotspotInteractionClass(selectedLayout);
}
if(shadowEl.isAtLeastSelected(1)) {
itemBuilder.removeHotspotInteractionClass(QTI21Constants.CSS_HOTSPOT_DISABLE_SHADOW);
} else {
itemBuilder.addHotspotInteractionClass(QTI21Constants.CSS_HOTSPOT_DISABLE_SHADOW);
}
fireEvent(ureq, new AssessmentItemEvent(AssessmentItemEvent.ASSESSMENT_ITEM_CHANGED, itemBuilder.getAssessmentItem(), QTI21QuestionType.hotspot)); fireEvent(ureq, new AssessmentItemEvent(AssessmentItemEvent.ASSESSMENT_ITEM_CHANGED, itemBuilder.getAssessmentItem(), QTI21QuestionType.hotspot));
} }
......
...@@ -6,7 +6,8 @@ ...@@ -6,7 +6,8 @@
maxChoices: 1, maxChoices: 1,
singleChoice: false, singleChoice: false,
responseValue: null, responseValue: null,
opened: false opened: false,
maphilightSettings: {}
}, options ); }, options );
try { try {
...@@ -31,7 +32,7 @@ ...@@ -31,7 +32,7 @@
var areaEl = jQuery('#ac_' + settings.responseIdentifier + '_' + areaIds[i]); var areaEl = jQuery('#ac_' + settings.responseIdentifier + '_' + areaIds[i]);
var data = areaEl.data('maphilight') || {}; var data = areaEl.data('maphilight') || {};
data.selectedOn = true; data.selectedOn = true;
colorData(data); colorData(data, settings.maphilightSettings);
areaEl.data('maphilight', data).trigger('alwaysOn.maphilight'); areaEl.data('maphilight', data).trigger('alwaysOn.maphilight');
var inputElement = jQuery('<input type="hidden"/>') var inputElement = jQuery('<input type="hidden"/>')
...@@ -45,12 +46,12 @@ ...@@ -45,12 +46,12 @@
var containerId = $obj.attr('id'); var containerId = $obj.attr('id');
jQuery('#' + containerId + " map area").each(function(index, el) { jQuery('#' + containerId + " map area").each(function(index, el) {
jQuery(el).on('click', function() { jQuery(el).on('click', function() {
clickHotspotArea(this, containerId, settings.responseIdentifier, settings.maxChoices, settings.singleChoice); clickHotspotArea(this, containerId, settings.responseIdentifier, settings.maxChoices, settings.singleChoice, settings.maphilightSettings);
}); });
}) })
}; };
function clickHotspotArea(spot, containerId, responseIdentifier, maxChoices, singleChoice) { function clickHotspotArea(spot, containerId, responseIdentifier, maxChoices, singleChoice, maphilightSettings) {
var areaEl = jQuery(spot); var areaEl = jQuery(spot);
var data = areaEl.data('maphilight') || {}; var data = areaEl.data('maphilight') || {};
if((typeof data.selectedOn === "undefined") || !data.selectedOn) { if((typeof data.selectedOn === "undefined") || !data.selectedOn) {
...@@ -59,7 +60,7 @@ ...@@ -59,7 +60,7 @@
var cData = jQuery(el).data('maphilight') || {}; var cData = jQuery(el).data('maphilight') || {};
if(cData.selectedOn) { if(cData.selectedOn) {
cData.selectedOn = false; cData.selectedOn = false;
colorData(cData); colorData(cData, maphilightSettings);
jQuery(el).data('maphilight', cData).trigger('alwaysOn.maphilight'); jQuery(el).data('maphilight', cData).trigger('alwaysOn.maphilight');
} }
}); });
...@@ -85,7 +86,7 @@ ...@@ -85,7 +86,7 @@
} else { } else {
data.selectedOn = !data.selectedOn; data.selectedOn = !data.selectedOn;
} }
colorData(data); colorData(data, maphilightSettings);
areaEl.data('maphilight', data).trigger('alwaysOn.maphilight'); areaEl.data('maphilight', data).trigger('alwaysOn.maphilight');
var divContainer = jQuery('#' + containerId); var divContainer = jQuery('#' + containerId);
...@@ -101,17 +102,17 @@ ...@@ -101,17 +102,17 @@
} }
}); });
}; };
/* /*
* Color the data based on the selectedOn flag * Color the data based on the selectedOn flag
*/ */
function colorData(data) { function colorData(data, maphilightSettings) {
if(data.selectedOn) { if(data.selectedOn) {
data.fillColor = '0000ff'; data.fillColor = maphilightSettings.selectedFillColor;
data.fillOpacity = 0.5; data.fillOpacity = maphilightSettings.selectedFillOpacity;
data.strokeColor = '0000ff'; data.strokeColor = maphilightSettings.selectedStrokeColor;
data.strokeOpacity = 1; data.strokeOpacity = maphilightSettings.selectedStrokeOpacity;
data.shadow = true; data.shadow = maphilightSettings.selectedShadow;
data.shadowX = 0; data.shadowX = 0;
data.shadowY = 0; data.shadowY = 0;
data.shadowRadius = 7; data.shadowRadius = 7;
...@@ -119,10 +120,10 @@ ...@@ -119,10 +120,10 @@
data.shadowOpacity = 0.8; data.shadowOpacity = 0.8;
data.shadowPosition = 'outside'; data.shadowPosition = 'outside';
} else { } else {
data.fillColor = 'bbbbbb'; data.fillColor = maphilightSettings.fillColor;
data.fillOpacity = 0.5; data.fillOpacity = maphilightSettings.fillOpacity;
data.strokeColor = '666666'; data.strokeColor = maphilightSettings.strokeColor;
data.strokeOpacity = 0.8; data.strokeOpacity = maphilightSettings.strokeOpacity;
data.shadow = false; data.shadow = false;
} }
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment