MDL-76106 qtype_ddmarker: Improve loading consistency.

Wait for the image to load completely before running the js.
This commit is contained in:
hieuvu
2022-12-02 12:34:43 +07:00
parent bdba78514f
commit ae949341cd
3 changed files with 64 additions and 5 deletions
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+62 -3
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();
}
/**
@@ -737,6 +739,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.