MDL-64393 drag-drop qtypes: be more robust when page layout changes
authorTim Hunt <T.J.Hunt@open.ac.uk>
Wed, 19 Dec 2018 13:49:25 +0000 (13:49 +0000)
committerTim Hunt <T.J.Hunt@open.ac.uk>
Fri, 11 Jan 2019 11:25:13 +0000 (11:25 +0000)
question/type/ddimageortext/amd/build/question.min.js
question/type/ddimageortext/amd/src/question.js
question/type/ddmarker/amd/build/question.min.js
question/type/ddmarker/amd/src/question.js

index caedf31..3b97e11 100644 (file)
Binary files a/question/type/ddimageortext/amd/build/question.min.js and b/question/type/ddimageortext/amd/build/question.min.js differ
index dd4cddc..a2327e9 100644 (file)
@@ -115,7 +115,6 @@ define(['jquery', 'core/dragdrop', 'core/key_codes'], function($, dragDrop, keys
         this.cloneDrags();
         this.positionDragsAndDrops();
         M.util.js_complete('qtype_ddimageortext-init-' + this.containerId);
-
     };
 
     /**
@@ -269,6 +268,28 @@ define(['jquery', 'core/dragdrop', 'core/key_codes'], function($, dragDrop, keys
                 .addClass('placed inplace' + place)
                 .offset(root.find('.dropzone.place' + place).offset());
         });
+
+        this.bgImage().data('prev-top', bgPosition.top).data('prev-left', bgPosition.left);
+    };
+
+    /**
+     * Check to see if the background image has moved. If so, refresh the layout.
+     */
+    DragDropOntoImageQuestion.prototype.fixLayoutIfBackgroundMoved = function() {
+        var bgImage = this.bgImage(),
+            bgPosition = bgImage.offset(),
+            prevTop = bgImage.data('prev-top'),
+            prevLeft = bgImage.data('prev-left');
+        if (prevLeft === undefined || prevTop === undefined) {
+            // Question is not set up yet. Nothing to do.
+            return;
+        }
+        if (prevTop === bgPosition.top && prevLeft === bgPosition.left) {
+            // Things have not moved.
+            return;
+        }
+        // We need to reposition things.
+        this.positionDragsAndDrops();
     };
 
     /**
@@ -698,6 +719,7 @@ define(['jquery', 'core/dragdrop', 'core/key_codes'], function($, dragDrop, keys
                     '.que.ddimageortext:not(.qtype_ddimageortext-readonly) .dropzones .dropzone',
                     questionManager.handleKeyPress);
             $(window).on('resize', questionManager.handleWindowResize);
+            setTimeout(questionManager.fixLayoutIfThingsMoved, 100);
         },
 
         /**
@@ -734,6 +756,24 @@ define(['jquery', 'core/dragdrop', 'core/key_codes'], function($, dragDrop, keys
             }
         },
 
+        /**
+         * Sometimes, despite our best efforts, things change in a way that cannot
+         * be specifically caught (e.g. dock expanding or collapsing in Boost).
+         * Therefore, we need to periodically check everything is in the right position.
+         */
+        fixLayoutIfThingsMoved: function() {
+            for (var containerId in questionManager.questions) {
+                if (questionManager.questions.hasOwnProperty(containerId)) {
+                    questionManager.questions[containerId].fixLayoutIfBackgroundMoved();
+                }
+            }
+
+            // We use setTimeout after finishing work, rather than setInterval,
+            // in case positioning things is slow. We want 100 ms gap
+            // between executions, not what setInterval does.
+            setTimeout(questionManager.fixLayoutIfThingsMoved, 100);
+        },
+
         /**
          * Given an event, work out which question it effects.
          * @param {Event} e the event.
index e9df3df..0f2b4f6 100644 (file)
Binary files a/question/type/ddmarker/amd/build/question.min.js and b/question/type/ddmarker/amd/build/question.min.js differ
index ff2a8af..ae812d8 100644 (file)
@@ -181,6 +181,10 @@ define(['jquery', 'core/dragdrop', 'qtype_ddmarker/shapes', 'core/key_codes'], f
         });
 
         this.repositionDropZones();
+
+        var bgImage = this.bgImage(),
+            bgPosition = bgImage.offset();
+        bgImage.data('prev-top', bgPosition.top).data('prev-left', bgPosition.left);
     };
 
     /**
@@ -487,6 +491,26 @@ define(['jquery', 'core/dragdrop', 'qtype_ddmarker/shapes', 'core/key_codes'], f
         this.repositionDrags();
     };
 
+    /**
+     * Check to see if the background image has moved. If so, refresh the layout.
+     */
+    DragDropMarkersQuestion.prototype.fixLayoutIfBackgroundMoved = function() {
+        var bgImage = this.bgImage(),
+            bgPosition = bgImage.offset(),
+            prevTop = bgImage.data('prev-top'),
+            prevLeft = bgImage.data('prev-left');
+        if (prevLeft === undefined || prevTop === undefined) {
+            // Question is not set up yet. Nothing to do.
+            return;
+        }
+        if (prevTop === bgPosition.top && prevLeft === bgPosition.left) {
+            // Things have not moved.
+            return;
+        }
+        // We need to reposition things.
+        this.repositionDrags();
+    };
+
     /**
      * Singleton that tracks all the DragDropToTextQuestions on this page, and deals
      * with event dispatching.
@@ -533,6 +557,7 @@ define(['jquery', 'core/dragdrop', 'qtype_ddmarker/shapes', 'core/key_codes'], f
                     '.que.ddmarker:not(.qtype_ddmarker-readonly) div.dragitems .dragitem',
                     questionManager.handleKeyPress);
             $(window).on('resize', questionManager.handleWindowResize);
+            setTimeout(questionManager.fixLayoutIfThingsMoved, 100);
         },
 
         /**
@@ -569,6 +594,24 @@ define(['jquery', 'core/dragdrop', 'qtype_ddmarker/shapes', 'core/key_codes'], f
             }
         },
 
+        /**
+         * Sometimes, despite our best efforts, things change in a way that cannot
+         * be specifically caught (e.g. dock expanding or collapsing in Boost).
+         * Therefore, we need to periodically check everything is in the right position.
+         */
+        fixLayoutIfThingsMoved: function() {
+            for (var containerId in questionManager.questions) {
+                if (questionManager.questions.hasOwnProperty(containerId)) {
+                    questionManager.questions[containerId].fixLayoutIfBackgroundMoved();
+                }
+            }
+
+            // We use setTimeout after finishing work, rather than setInterval,
+            // in case positioning things is slow. We want 100 ms gap
+            // between executions, not what setInterval does.
+            setTimeout(questionManager.fixLayoutIfThingsMoved, 100);
+        },
+
         /**
          * Given an event, work out which question it effects.
          * @param {Event} e the event.