Merge branch 'MDL-76106-401' of https://github.com/NashTechOpenUniversity/moodle into MOODLE_401_STABLE

This commit is contained in:
Sara Arjona 2023-01-02 13:07:39 +01:00
commit e2c8f3db7c
4 changed files with 140 additions and 20 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -57,9 +57,11 @@ define([
if (readOnly) {
this.getRoot().addClass('qtype_ddmarker-readonly');
}
thisQ.cloneDrags();
thisQ.repositionDrags();
thisQ.drawDropzones();
thisQ.allImagesLoaded = false;
thisQ.getNotYetLoadedImages().one('load', function() {
thisQ.waitForAllImagesToBeLoaded();
});
thisQ.waitForAllImagesToBeLoaded();
}
/**
@ -147,13 +149,17 @@ define([
root.find('input.choices').each(function(key, input) {
var choiceNo = thisQ.getChoiceNoFromElement(input),
coords = thisQ.getCoords(input);
if (coords.length) {
imageCoords = thisQ.getImageCoords(input);
if (imageCoords.length) {
var drag = thisQ.getRoot().find('.draghomes' + ' span.marker' + '.choice' + choiceNo).not('.dragplaceholder');
drag.remove();
for (var i = 0; i < coords.length; i++) {
for (var i = 0; i < imageCoords.length; i++) {
var dragInDrop = drag.clone();
dragInDrop.data('pagex', coords[i].x).data('pagey', coords[i].y);
// Convert image coords to screen coords.
const screenCoords = thisQ.convertToWindowXY(imageCoords[i]);
dragInDrop.data('pagex', screenCoords.x).data('pagey', screenCoords.y);
// Save image coords to the drag item so we can use it later.
dragInDrop.data('imageCoords', imageCoords[i]);
// We always save the coordinates in the 1:1 ratio.
// So we need to set the scale ratio to 1 for the initial load.
dragInDrop.data('scaleRatio', 1);
@ -214,18 +220,18 @@ define([
* drags should be shown.
*
* @param {jQuery} inputNode
* @returns {Point[]} coordinates of however many copies of the drag item should be shown.
* @returns {Point[]} image coordinates of however many copies of the drag item should be shown.
*/
DragDropMarkersQuestion.prototype.getCoords = function(inputNode) {
var coords = [],
DragDropMarkersQuestion.prototype.getImageCoords = function(inputNode) {
var imageCoords = [],
val = $(inputNode).val();
if (val !== '') {
var coordsStrings = val.split(';');
for (var i = 0; i < coordsStrings.length; i++) {
coords[i] = this.convertToWindowXY(Shapes.Point.parse(coordsStrings[i]));
imageCoords[i] = Shapes.Point.parse(coordsStrings[i]);
}
}
return coords;
return imageCoords;
};
/**
@ -328,7 +334,12 @@ define([
if (this.coordsInBgImg(dragXY)) {
this.sendDragToDrop(dragged, true);
placed = true;
// Since we already move the drag item to new position.
// Remove the image coords if this drag item have it.
// We will get the new image coords for this drag item in saveCoordsForChoice.
if (dragged.data('imageCoords')) {
dragged.data('imageCoords', null);
}
// It seems that the dragdrop sometimes leaves the drag
// one pixel out of position. Put it in exactly the right place.
var bgImgXY = this.convertToBgImgXY(dragXY);
@ -351,15 +362,15 @@ define([
* @param {Number} choiceNo which copy of the choice this was.
*/
DragDropMarkersQuestion.prototype.saveCoordsForChoice = function(choiceNo) {
var coords = [],
items = this.getRoot().find('div.droparea span.marker.choice' + choiceNo),
let imageCoords = [];
var items = this.getRoot().find('div.droparea span.marker.choice' + choiceNo),
thiQ = this,
bgRatio = this.bgRatio();
if (items.length) {
items.each(function() {
var drag = $(this);
if (!drag.hasClass('beingdragged')) {
if (!drag.hasClass('beingdragged') && !drag.data('imageCoords')) {
if (drag.data('scaleRatio') !== bgRatio) {
// The scale ratio for the draggable item was changed. We need to update that.
drag.data('pagex', drag.offset().left).data('pagey', drag.offset().top);
@ -368,13 +379,15 @@ define([
if (thiQ.coordsInBgImg(dragXY)) {
var bgImgXY = thiQ.convertToBgImgXY(dragXY);
bgImgXY = new Shapes.Point(bgImgXY.x / bgRatio, bgImgXY.y / bgRatio);
coords[coords.length] = bgImgXY;
imageCoords[imageCoords.length] = bgImgXY;
}
} else if (drag.data('imageCoords')) {
imageCoords[imageCoords.length] = drag.data('imageCoords');
}
});
}
this.getRoot().find('input.choice' + choiceNo).val(coords.join(';'));
this.getRoot().find('input.choice' + choiceNo).val(imageCoords.join(';'));
if (this.isQuestionInteracted()) {
// The user has interacted with the draggable items. We need to mark the form as dirty.
questionManager.handleFormDirty();
@ -737,6 +750,63 @@ define([
return drag.hasClass('infinite');
};
/**
* Waits until all images are loaded before calling setupQuestion().
*
* This function is called from the onLoad of each image, and also polls with
* a time-out, because image on-loads are allegedly unreliable.
*/
DragDropMarkersQuestion.prototype.waitForAllImagesToBeLoaded = function() {
// This method may get called multiple times (via image on-loads or timeouts.
// If we are already done, don't do it again.
if (this.allImagesLoaded) {
return;
}
// Clear any current timeout, if set.
if (this.imageLoadingTimeoutId !== null) {
clearTimeout(this.imageLoadingTimeoutId);
}
// If we have not yet loaded all images, set a timeout to
// call ourselves again, since apparently images on-load
// events are flakey.
if (this.getNotYetLoadedImages().length > 0) {
this.imageLoadingTimeoutId = setTimeout(function() {
this.waitForAllImagesToBeLoaded();
}, 100);
return;
}
// We now have all images. Carry on, but only after giving the layout a chance to settle down.
this.allImagesLoaded = true;
this.cloneDrags();
this.repositionDrags();
this.drawDropzones();
};
/**
* Get any of the images in the drag-drop area that are not yet fully loaded.
*
* @returns {jQuery} those images.
*/
DragDropMarkersQuestion.prototype.getNotYetLoadedImages = function() {
return this.getRoot().find('.ddmarker img.dropbackground').not(function(i, imgNode) {
return this.imageIsLoaded(imgNode);
});
};
/**
* Check if an image has loaded without errors.
*
* @param {HTMLImageElement} imgElement an image.
* @returns {boolean} true if this image has loaded without errors.
*/
DragDropMarkersQuestion.prototype.imageIsLoaded = function(imgElement) {
return imgElement.complete && imgElement.naturalHeight !== 0;
};
/**
* Singleton that tracks all the DragDropToTextQuestions on this page, and deals
* with event dispatching.

View File

@ -0,0 +1,50 @@
@qtype @qtype_ddmarker
Feature: Preview a quiz with multiple maker question.
As a teacher
In order to check my drag-drop marker questions will work for students
I need to preview them in quiz with multiple questions.
Background:
And the following "courses" exist:
| fullname | shortname | category |
| Course 1 | C1 | 0 |
And the following "question categories" exist:
| contextlevel | reference | name |
| Course | C1 | Test questions |
And the following "questions" exist:
| questioncategory | qtype | name | template |
| Test questions | ddmarker | Drag markers | mkmap |
| Test questions | ddmarker | Drag markers 2 | mkmap |
And the following "activities" exist:
| activity | name | course | idnumber |
| quiz | Test quiz | C1 | quiz1 |
And quiz "Test quiz" contains the following questions:
| Drag markers | 1 |
| Drag markers 2 | 2 |
@javascript
Scenario: Preview a quiz with multiple markers question
Given I am on the "Test quiz" "mod_quiz > View" page logged in as "admin"
And I press "Preview quiz"
# Add change window size so we can drag-drop OU marker on 322,213 coordinates on firefox.
And I change viewport size to "large"
# Drag items and go back and forth between the question.
And I drag "OU" to "322,213" in the drag and drop markers question
And I drag "Railway station" to "144,84" in the drag and drop markers question
And I drag "Railway station" to "195,180" in the drag and drop markers question
And I press "Next page"
And I drag "OU" to "322,213" in the drag and drop markers question
And I drag "Railway station" to "144,84" in the drag and drop markers question
And I drag "Railway station" to "195,180" in the drag and drop markers question
And I press "Previous page"
And I drag "Railway station" to "267,302" in the drag and drop markers question
And I press "Next page"
And I drag "Railway station" to "267,302" in the drag and drop markers question
And I press "Previous page"
And I press "Next page"
And I press "Finish attempt ..."
And I press "Submit all and finish"
When I click on "Submit all and finish" "button" in the "Submit all your answers and finish?" "dialogue"
Then I should see "2.00/2.00"
And the state of "Please place the markers on the map of Milton Keynes and be aware that" question is shown as "Correct"
And I should see "Well done!"