MDL-71344 questions: Improve event handler for Drag n Drop family
[moodle.git] / question / type / ddimageortext / amd / build / question.min.js.map
blobc14b5550650004b50fc9b5b890cf43e82a74ccf3
1 {"version":3,"sources":["../src/question.js"],"names":["define","$","dragDrop","keys","DragDropOntoImageQuestion","containerId","readOnly","places","M","util","js_pending","allImagesLoaded","imageLoadingTimeoutId","isPrinting","getRoot","addClass","thisQ","getNotYetLoadedImages","one","waitForAllImagesToBeLoaded","prototype","clearTimeout","length","setTimeout","setupQuestion","find","not","i","imgNode","imageIsLoaded","imgElement","complete","naturalHeight","resizeAllDragsAndDrops","cloneDrags","positionDragsAndDrops","js_complete","each","node","resizeAllDragsAndDropsInGroup","getClassnameNumericSuffix","group","root","dragHomes","maxWidth","maxHeight","drag","Math","max","ceil","offsetWidth","offsetHeight","left","round","top","floor","css","hasOwnProperty","place","label","text","parseInt","get_string","append","width","height","index","dragHome","placeHolder","clone","removeClass","getChoice","getGroup","before","cloneDragsForOneChoice","hasClass","noOfDrags","noOfDropsInGroup","cloneDrag","offset","bgRatio","dropNode","drop","getPlace","xy","data","handleElementScale","dragNode","currentPlace","removeAttr","inputNode","input","choice","val","unplacedDrag","getUnplacedChoice","hiddenDrag","getDragClone","getInfiniteDragClones","after","sendDragToDrop","handleDragStart","e","target","closest","currentIndex","calculateZIndex","info","prepare","start","setInputValue","hiddenDrop","getDrop","questionManager","addEventHandlersToDrag","x","y","dragMove","dragEnd","pageX","pageY","highlighted","isPointInDrop","isDragSameAsDrop","placed","placedNode","placedDrag","sendDragHome","oldDrag","getCurrentDragInPlace","focus","attr","animateTo","getDragHome","handleKeyPress","currentDrag","nextDrag","keyCode","space","arrowRight","arrowDown","getNextDrag","arrowLeft","arrowUp","getPreviousDrag","escape","isKeyboardNavigation","preventDefault","numChoices","noOfChoicesInGroup","next","previous","currentPos","targetPos","animate","duration","done","trigger","position","outerWidth","outerHeight","document","getElementById","bgImage","is","slice","prefix","classes","classesArr","split","patt1","RegExp","test","match","exec","inHome","handleResize","parseFloat","key","bgImg","bgImgNaturalWidth","get","naturalWidth","bgImgClientWidth","element","type","zIndex","itemZIndex","eventHandlersInitialised","dragEventHandlersInitialised","questions","init","setupEventHandlers","questionContainer","classList","contains","on","handleDragMoved","window","handleWindowResize","addEventListener","fixLayoutIfThingsMoved","unbind","question","getQuestionForEvent","removeData","first","remove","currentTarget"],"mappings":"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","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.\n\n/*\n * JavaScript to allow dragging options to slots (using mouse down or touch) or tab through slots using keyboard.\n *\n * @module     qtype_ddimageortext/question\n * @copyright  2018 The Open University\n * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\ndefine(['jquery', 'core/dragdrop', 'core/key_codes'], function($, dragDrop, keys) {\n\n    \"use strict\";\n\n    /**\n     * Initialise one drag-drop onto image question.\n     *\n     * @param {String} containerId id of the outer div for this question.\n     * @param {boolean} readOnly whether the question is being displayed read-only.\n     * @param {Array} places Information about the drop places.\n     * @constructor\n     */\n    function DragDropOntoImageQuestion(containerId, readOnly, places) {\n        this.containerId = containerId;\n        M.util.js_pending('qtype_ddimageortext-init-' + this.containerId);\n        this.places = places;\n        this.allImagesLoaded = false;\n        this.imageLoadingTimeoutId = null;\n        this.isPrinting = false;\n        if (readOnly) {\n            this.getRoot().addClass('qtype_ddimageortext-readonly');\n        }\n\n        var thisQ = this;\n        this.getNotYetLoadedImages().one('load', function() {\n            thisQ.waitForAllImagesToBeLoaded();\n        });\n        this.waitForAllImagesToBeLoaded();\n    }\n\n    /**\n     * Waits until all images are loaded before calling setupQuestion().\n     *\n     * This function is called from the onLoad of each image, and also polls with\n     * a time-out, because image on-loads are allegedly unreliable.\n     */\n    DragDropOntoImageQuestion.prototype.waitForAllImagesToBeLoaded = function() {\n        var thisQ = this;\n\n        // This method may get called multiple times (via image on-loads or timeouts.\n        // If we are already done, don't do it again.\n        if (this.allImagesLoaded) {\n            return;\n        }\n\n        // Clear any current timeout, if set.\n        if (this.imageLoadingTimeoutId !== null) {\n            clearTimeout(this.imageLoadingTimeoutId);\n        }\n\n        // If we have not yet loaded all images, set a timeout to\n        // call ourselves again, since apparently images on-load\n        // events are flakey.\n        if (this.getNotYetLoadedImages().length > 0) {\n            this.imageLoadingTimeoutId = setTimeout(function() {\n                thisQ.waitForAllImagesToBeLoaded();\n            }, 100);\n            return;\n        }\n\n        // We now have all images. Carry on, but only after giving the layout a chance to settle down.\n        this.allImagesLoaded = true;\n        thisQ.setupQuestion();\n    };\n\n    /**\n     * Get any of the images in the drag-drop area that are not yet fully loaded.\n     *\n     * @returns {jQuery} those images.\n     */\n    DragDropOntoImageQuestion.prototype.getNotYetLoadedImages = function() {\n        var thisQ = this;\n        return this.getRoot().find('.ddarea img').not(function(i, imgNode) {\n            return thisQ.imageIsLoaded(imgNode);\n        });\n    };\n\n    /**\n     * Check if an image has loaded without errors.\n     *\n     * @param {HTMLImageElement} imgElement an image.\n     * @returns {boolean} true if this image has loaded without errors.\n     */\n    DragDropOntoImageQuestion.prototype.imageIsLoaded = function(imgElement) {\n        return imgElement.complete && imgElement.naturalHeight !== 0;\n    };\n\n    /**\n     * Set up the question, once all images have been loaded.\n     */\n    DragDropOntoImageQuestion.prototype.setupQuestion = function() {\n        this.resizeAllDragsAndDrops();\n        this.cloneDrags();\n        this.positionDragsAndDrops();\n        M.util.js_complete('qtype_ddimageortext-init-' + this.containerId);\n    };\n\n    /**\n     * In each group, resize all the items to be the same size.\n     */\n    DragDropOntoImageQuestion.prototype.resizeAllDragsAndDrops = function() {\n        var thisQ = this;\n        this.getRoot().find('.draghomes > div').each(function(i, node) {\n            thisQ.resizeAllDragsAndDropsInGroup(\n                    thisQ.getClassnameNumericSuffix($(node), 'dragitemgroup'));\n        });\n    };\n\n    /**\n     * In a given group, set all the drags and drops to be the same size.\n     *\n     * @param {int} group the group number.\n     */\n    DragDropOntoImageQuestion.prototype.resizeAllDragsAndDropsInGroup = function(group) {\n        var root = this.getRoot(),\n            dragHomes = root.find('.dragitemgroup' + group + ' .draghome'),\n            maxWidth = 0,\n            maxHeight = 0;\n\n        // Find the maximum size of any drag in this groups.\n        dragHomes.each(function(i, drag) {\n            maxWidth = Math.max(maxWidth, Math.ceil(drag.offsetWidth));\n            maxHeight = Math.max(maxHeight, Math.ceil(drag.offsetHeight));\n        });\n\n        // The size we will want to set is a bit bigger than this.\n        maxWidth += 10;\n        maxHeight += 10;\n\n        // Set each drag home to that size.\n        dragHomes.each(function(i, drag) {\n            var left = Math.round((maxWidth - drag.offsetWidth) / 2),\n                top = Math.floor((maxHeight - drag.offsetHeight) / 2);\n            // Set top and left padding so the item is centred.\n            $(drag).css({\n                'padding-left': left + 'px',\n                'padding-right': (maxWidth - drag.offsetWidth - left) + 'px',\n                'padding-top': top + 'px',\n                'padding-bottom': (maxHeight - drag.offsetHeight - top) + 'px'\n            });\n        });\n\n        // Create the drops and make them the right size.\n        for (var i in this.places) {\n            if (!this.places.hasOwnProperty((i))) {\n                continue;\n            }\n            var place = this.places[i],\n                label = place.text;\n            if (parseInt(place.group) !== group) {\n                continue;\n            }\n            if (label === '') {\n                label = M.util.get_string('blank', 'qtype_ddimageortext');\n            }\n            root.find('.dropzones').append('<div class=\"dropzone active group' + place.group +\n                            ' place' + i + '\" tabindex=\"0\">' +\n                    '<span class=\"accesshide\">' + label + '</span>&nbsp;</div>');\n            root.find('.dropzone.place' + i).width(maxWidth - 2).height(maxHeight - 2);\n        }\n    };\n\n    /**\n     * Invisible 'drag homes' are output by the renderer. These have the same properties\n     * as the drag items but are invisible. We clone these invisible elements to make the\n     * actual drag items.\n     */\n    DragDropOntoImageQuestion.prototype.cloneDrags = function() {\n        var thisQ = this;\n        thisQ.getRoot().find('.draghome').each(function(index, dragHome) {\n            var drag = $(dragHome);\n            var placeHolder = drag.clone();\n            placeHolder.removeClass();\n            placeHolder.addClass('draghome choice' +\n                thisQ.getChoice(drag) + ' group' +\n                thisQ.getGroup(drag) + ' dragplaceholder');\n            drag.before(placeHolder);\n        });\n    };\n\n    /**\n     * Clone drag item for one choice.\n     *\n     * @param {jQuery} dragHome the drag home to clone.\n     */\n    DragDropOntoImageQuestion.prototype.cloneDragsForOneChoice = function(dragHome) {\n        if (dragHome.hasClass('infinite')) {\n            var noOfDrags = this.noOfDropsInGroup(this.getGroup(dragHome));\n            for (var i = 0; i < noOfDrags; i++) {\n                this.cloneDrag(dragHome);\n            }\n        } else {\n            this.cloneDrag(dragHome);\n        }\n    };\n\n    /**\n     * Clone drag item.\n     *\n     * @param {jQuery} dragHome\n     */\n    DragDropOntoImageQuestion.prototype.cloneDrag = function(dragHome) {\n        var drag = dragHome.clone();\n        drag.removeClass('draghome')\n            .addClass('drag unplaced moodle-has-zindex')\n            .offset(dragHome.offset());\n        this.getRoot().find('.dragitems').append(drag);\n    };\n\n    /**\n     * Update the position of drags.\n     */\n    DragDropOntoImageQuestion.prototype.positionDragsAndDrops = function() {\n        var thisQ = this,\n            root = this.getRoot(),\n            bgRatio = this.bgRatio();\n\n        // Move the drops into position.\n        root.find('.ddarea .dropzone').each(function(i, dropNode) {\n            var drop = $(dropNode),\n                place = thisQ.places[thisQ.getPlace(drop)];\n            // The xy values come from PHP as strings, so we need parseInt to stop JS doing string concatenation.\n            drop.css('left', parseInt(place.xy[0]) * bgRatio)\n                .css('top', parseInt(place.xy[1]) * bgRatio);\n            drop.data('originX', parseInt(place.xy[0]))\n                .data('originY', parseInt(place.xy[1]));\n            thisQ.handleElementScale(drop, 'left top');\n        });\n\n        // First move all items back home.\n        root.find('.draghome').not('.dragplaceholder').each(function(i, dragNode) {\n            var drag = $(dragNode),\n                currentPlace = thisQ.getClassnameNumericSuffix(drag, 'inplace');\n            drag.addClass('unplaced')\n                .removeClass('placed');\n            drag.removeAttr('tabindex');\n            if (currentPlace !== null) {\n                drag.removeClass('inplace' + currentPlace);\n            }\n        });\n\n        // Then place the ones that should be placed.\n        root.find('input.placeinput').each(function(i, inputNode) {\n            var input = $(inputNode),\n                choice = input.val();\n            if (choice.length === 0 || (choice.length > 0 && choice === '0')) {\n                // No item in this place.\n                return;\n            }\n\n            var place = thisQ.getPlace(input);\n            // Get the unplaced drag.\n            var unplacedDrag = thisQ.getUnplacedChoice(thisQ.getGroup(input), choice);\n            // Get the clone of the drag.\n            var hiddenDrag = thisQ.getDragClone(unplacedDrag);\n            if (hiddenDrag.length) {\n                if (unplacedDrag.hasClass('infinite')) {\n                    var noOfDrags = thisQ.noOfDropsInGroup(thisQ.getGroup(unplacedDrag));\n                    var cloneDrags = thisQ.getInfiniteDragClones(unplacedDrag, false);\n                    if (cloneDrags.length < noOfDrags) {\n                        var cloneDrag = unplacedDrag.clone();\n                        cloneDrag.removeClass('beingdragged');\n                        cloneDrag.removeAttr('tabindex');\n                        hiddenDrag.after(cloneDrag);\n                    } else {\n                        hiddenDrag.addClass('active');\n                    }\n                } else {\n                    hiddenDrag.addClass('active');\n                }\n            }\n\n            // Send the drag to drop.\n            var drop = root.find('.dropzone.place' + place);\n            thisQ.sendDragToDrop(unplacedDrag, drop);\n        });\n    };\n\n    /**\n     * Handles the start of dragging an item.\n     *\n     * @param {Event} e the touch start or mouse down event.\n     */\n    DragDropOntoImageQuestion.prototype.handleDragStart = function(e) {\n        var thisQ = this,\n            drag = $(e.target).closest('.draghome'),\n            currentIndex = this.calculateZIndex(),\n            newIndex = currentIndex + 2;\n\n        var info = dragDrop.prepare(e);\n        if (!info.start) {\n            return;\n        }\n\n        drag.addClass('beingdragged').css('transform', '').css('z-index', newIndex);\n        var currentPlace = this.getClassnameNumericSuffix(drag, 'inplace');\n        if (currentPlace !== null) {\n            this.setInputValue(currentPlace, 0);\n            drag.removeClass('inplace' + currentPlace);\n            var hiddenDrop = thisQ.getDrop(drag, currentPlace);\n            if (hiddenDrop.length) {\n                hiddenDrop.addClass('active');\n                drag.offset(hiddenDrop.offset());\n            }\n        } else {\n            var hiddenDrag = thisQ.getDragClone(drag);\n            if (hiddenDrag.length) {\n                if (drag.hasClass('infinite')) {\n                    var noOfDrags = this.noOfDropsInGroup(thisQ.getGroup(drag));\n                    var cloneDrags = this.getInfiniteDragClones(drag, false);\n                    if (cloneDrags.length < noOfDrags) {\n                        var cloneDrag = drag.clone();\n                        cloneDrag.removeClass('beingdragged');\n                        cloneDrag.removeAttr('tabindex');\n                        hiddenDrag.after(cloneDrag);\n                        questionManager.addEventHandlersToDrag(cloneDrag);\n                        drag.offset(cloneDrag.offset());\n                    } else {\n                        hiddenDrag.addClass('active');\n                        drag.offset(hiddenDrag.offset());\n                    }\n                } else {\n                    hiddenDrag.addClass('active');\n                    drag.offset(hiddenDrag.offset());\n                }\n            }\n        }\n\n        dragDrop.start(e, drag, function(x, y, drag) {\n            thisQ.dragMove(x, y, drag);\n        }, function(x, y, drag) {\n            thisQ.dragEnd(x, y, drag);\n        });\n    };\n\n    /**\n     * Called whenever the currently dragged items moves.\n     *\n     * @param {Number} pageX the x position.\n     * @param {Number} pageY the y position.\n     * @param {jQuery} drag the item being moved.\n     */\n    DragDropOntoImageQuestion.prototype.dragMove = function(pageX, pageY, drag) {\n        var thisQ = this,\n            highlighted = false;\n        this.getRoot().find('.dropzone.group' + this.getGroup(drag)).each(function(i, dropNode) {\n            var drop = $(dropNode);\n            if (thisQ.isPointInDrop(pageX, pageY, drop) && !highlighted) {\n                highlighted = true;\n                drop.addClass('valid-drag-over-drop');\n            } else {\n                drop.removeClass('valid-drag-over-drop');\n            }\n        });\n        this.getRoot().find('.draghome.placed.group' + this.getGroup(drag)).not('.beingdragged').each(function(i, dropNode) {\n            var drop = $(dropNode);\n            if (thisQ.isPointInDrop(pageX, pageY, drop) && !highlighted && !thisQ.isDragSameAsDrop(drag, drop)) {\n                highlighted = true;\n                drop.addClass('valid-drag-over-drop');\n            } else {\n                drop.removeClass('valid-drag-over-drop');\n            }\n        });\n    };\n\n    /**\n     * Called when user drops a drag item.\n     *\n     * @param {Number} pageX the x position.\n     * @param {Number} pageY the y position.\n     * @param {jQuery} drag the item being moved.\n     */\n    DragDropOntoImageQuestion.prototype.dragEnd = function(pageX, pageY, drag) {\n        var thisQ = this,\n            root = this.getRoot(),\n            placed = false;\n\n        // Looking for drag that was dropped on a dropzone.\n        root.find('.dropzone.group' + this.getGroup(drag)).each(function(i, dropNode) {\n            var drop = $(dropNode);\n            if (!thisQ.isPointInDrop(pageX, pageY, drop)) {\n                // Not this drop.\n                return true;\n            }\n\n            // Now put this drag into the drop.\n            drop.removeClass('valid-drag-over-drop');\n            thisQ.sendDragToDrop(drag, drop);\n            placed = true;\n            return false; // Stop the each() here.\n        });\n\n        if (!placed) {\n            // Looking for drag that was dropped on a placed drag.\n            root.find('.draghome.placed.group' + this.getGroup(drag)).not('.beingdragged').each(function(i, placedNode) {\n                var placedDrag = $(placedNode);\n                if (!thisQ.isPointInDrop(pageX, pageY, placedDrag) || thisQ.isDragSameAsDrop(drag, placedDrag)) {\n                    // Not this placed drag.\n                    return true;\n                }\n\n                // Now put this drag into the drop.\n                placedDrag.removeClass('valid-drag-over-drop');\n                var currentPlace = thisQ.getClassnameNumericSuffix(placedDrag, 'inplace');\n                var drop = thisQ.getDrop(drag, currentPlace);\n                thisQ.sendDragToDrop(drag, drop);\n                placed = true;\n                return false; // Stop the each() here.\n            });\n        }\n\n        if (!placed) {\n            this.sendDragHome(drag);\n        }\n    };\n\n    /**\n     * Animate a drag item into a given place (or back home).\n     *\n     * @param {jQuery|null} drag the item to place. If null, clear the place.\n     * @param {jQuery} drop the place to put it.\n     */\n    DragDropOntoImageQuestion.prototype.sendDragToDrop = function(drag, drop) {\n        // Is there already a drag in this drop? if so, evict it.\n        var oldDrag = this.getCurrentDragInPlace(this.getPlace(drop));\n        if (oldDrag.length !== 0) {\n            oldDrag.addClass('beingdragged');\n            oldDrag.offset(oldDrag.offset());\n            var currentPlace = this.getClassnameNumericSuffix(oldDrag, 'inplace');\n            var hiddenDrop = this.getDrop(oldDrag, currentPlace);\n            hiddenDrop.addClass('active');\n            this.sendDragHome(oldDrag);\n        }\n\n        if (drag.length === 0) {\n            this.setInputValue(this.getPlace(drop), 0);\n            if (drop.data('isfocus')) {\n                drop.focus();\n            }\n        } else {\n            this.setInputValue(this.getPlace(drop), this.getChoice(drag));\n            drag.removeClass('unplaced')\n                .addClass('placed inplace' + this.getPlace(drop));\n            drag.attr('tabindex', 0);\n            this.animateTo(drag, drop);\n        }\n    };\n\n    /**\n     * Animate a drag back to its home.\n     *\n     * @param {jQuery} drag the item being moved.\n     */\n    DragDropOntoImageQuestion.prototype.sendDragHome = function(drag) {\n        var currentPlace = this.getClassnameNumericSuffix(drag, 'inplace');\n        if (currentPlace !== null) {\n            drag.removeClass('inplace' + currentPlace);\n        }\n        drag.data('unplaced', true);\n\n        this.animateTo(drag, this.getDragHome(this.getGroup(drag), this.getChoice(drag)));\n    };\n\n    /**\n     * Handles keyboard events on drops.\n     *\n     * Drops are focusable. Once focused, right/down/space switches to the next choice, and\n     * left/up switches to the previous. Escape clear.\n     *\n     * @param {KeyboardEvent} e\n     */\n    DragDropOntoImageQuestion.prototype.handleKeyPress = function(e) {\n        var drop = $(e.target).closest('.dropzone');\n        if (drop.length === 0) {\n            var placedDrag = $(e.target);\n            var currentPlace = this.getClassnameNumericSuffix(placedDrag, 'inplace');\n            if (currentPlace !== null) {\n                drop = this.getDrop(placedDrag, currentPlace);\n            }\n        }\n        var currentDrag = this.getCurrentDragInPlace(this.getPlace(drop)),\n            nextDrag = $();\n\n        switch (e.keyCode) {\n            case keys.space:\n            case keys.arrowRight:\n            case keys.arrowDown:\n                nextDrag = this.getNextDrag(this.getGroup(drop), currentDrag);\n                break;\n\n            case keys.arrowLeft:\n            case keys.arrowUp:\n                nextDrag = this.getPreviousDrag(this.getGroup(drop), currentDrag);\n                break;\n\n            case keys.escape:\n                questionManager.isKeyboardNavigation = false;\n                break;\n\n            default:\n                questionManager.isKeyboardNavigation = false;\n                return; // To avoid the preventDefault below.\n        }\n\n        if (nextDrag.length) {\n            nextDrag.data('isfocus', true);\n            nextDrag.addClass('beingdragged');\n            var hiddenDrag = this.getDragClone(nextDrag);\n            if (hiddenDrag.length) {\n                if (nextDrag.hasClass('infinite')) {\n                    var noOfDrags = this.noOfDropsInGroup(this.getGroup(nextDrag));\n                    var cloneDrags = this.getInfiniteDragClones(nextDrag, false);\n                    if (cloneDrags.length < noOfDrags) {\n                        var cloneDrag = nextDrag.clone();\n                        cloneDrag.removeClass('beingdragged');\n                        cloneDrag.removeAttr('tabindex');\n                        hiddenDrag.after(cloneDrag);\n                        questionManager.addEventHandlersToDrag(cloneDrag);\n                        nextDrag.offset(cloneDrag.offset());\n                    } else {\n                        hiddenDrag.addClass('active');\n                        nextDrag.offset(hiddenDrag.offset());\n                    }\n                } else {\n                    hiddenDrag.addClass('active');\n                    nextDrag.offset(hiddenDrag.offset());\n                }\n            }\n        } else {\n            drop.data('isfocus', true);\n        }\n\n        e.preventDefault();\n        this.sendDragToDrop(nextDrag, drop);\n    };\n\n    /**\n     * Choose the next drag in a group.\n     *\n     * @param {int} group which group.\n     * @param {jQuery} drag current choice (empty jQuery if there isn't one).\n     * @return {jQuery} the next drag in that group, or null if there wasn't one.\n     */\n    DragDropOntoImageQuestion.prototype.getNextDrag = function(group, drag) {\n        var choice,\n            numChoices = this.noOfChoicesInGroup(group);\n\n        if (drag.length === 0) {\n            choice = 1; // Was empty, so we want to select the first choice.\n        } else {\n            choice = this.getChoice(drag) + 1;\n        }\n\n        var next = this.getUnplacedChoice(group, choice);\n        while (next.length === 0 && choice < numChoices) {\n            choice++;\n            next = this.getUnplacedChoice(group, choice);\n        }\n\n        return next;\n    };\n\n    /**\n     * Choose the previous drag in a group.\n     *\n     * @param {int} group which group.\n     * @param {jQuery} drag current choice (empty jQuery if there isn't one).\n     * @return {jQuery} the next drag in that group, or null if there wasn't one.\n     */\n    DragDropOntoImageQuestion.prototype.getPreviousDrag = function(group, drag) {\n        var choice;\n\n        if (drag.length === 0) {\n            choice = this.noOfChoicesInGroup(group);\n        } else {\n            choice = this.getChoice(drag) - 1;\n        }\n\n        var previous = this.getUnplacedChoice(group, choice);\n        while (previous.length === 0 && choice > 1) {\n            choice--;\n            previous = this.getUnplacedChoice(group, choice);\n        }\n\n        // Does this choice exist?\n        return previous;\n    };\n\n    /**\n     * Animate an object to the given destination.\n     *\n     * @param {jQuery} drag the element to be animated.\n     * @param {jQuery} target element marking the place to move it to.\n     */\n    DragDropOntoImageQuestion.prototype.animateTo = function(drag, target) {\n        var currentPos = drag.offset(),\n            targetPos = target.offset(),\n            thisQ = this;\n\n        M.util.js_pending('qtype_ddimageortext-animate-' + thisQ.containerId);\n        // Animate works in terms of CSS position, whereas locating an object\n        // on the page works best with jQuery offset() function. So, to get\n        // the right target position, we work out the required change in\n        // offset() and then add that to the current CSS position.\n        drag.animate(\n            {\n                left: parseInt(drag.css('left')) + targetPos.left - currentPos.left,\n                top: parseInt(drag.css('top')) + targetPos.top - currentPos.top\n            },\n            {\n                duration: 'fast',\n                done: function() {\n                    $('body').trigger('qtype_ddimageortext-dragmoved', [drag, target, thisQ]);\n                    M.util.js_complete('qtype_ddimageortext-animate-' + thisQ.containerId);\n                }\n            }\n        );\n    };\n\n    /**\n     * Detect if a point is inside a given DOM node.\n     *\n     * @param {Number} pageX the x position.\n     * @param {Number} pageY the y position.\n     * @param {jQuery} drop the node to check (typically a drop).\n     * @return {boolean} whether the point is inside the node.\n     */\n    DragDropOntoImageQuestion.prototype.isPointInDrop = function(pageX, pageY, drop) {\n        var position = drop.offset();\n        if (drop.hasClass('draghome')) {\n            return pageX >= position.left && pageX < position.left + drop.outerWidth()\n                && pageY >= position.top && pageY < position.top + drop.outerHeight();\n        }\n        return pageX >= position.left && pageX < position.left + drop.width()\n            && pageY >= position.top && pageY < position.top + drop.height();\n    };\n\n    /**\n     * Set the value of the hidden input for a place, to record what is currently there.\n     *\n     * @param {int} place which place to set the input value for.\n     * @param {int} choice the value to set.\n     */\n    DragDropOntoImageQuestion.prototype.setInputValue = function(place, choice) {\n        this.getRoot().find('input.placeinput.place' + place).val(choice);\n    };\n\n    /**\n     * Get the outer div for this question.\n     *\n     * @returns {jQuery} containing that div.\n     */\n    DragDropOntoImageQuestion.prototype.getRoot = function() {\n        return $(document.getElementById(this.containerId));\n    };\n\n    /**\n     * Get the img that is the background image.\n     * @returns {jQuery} containing that img.\n     */\n    DragDropOntoImageQuestion.prototype.bgImage = function() {\n        return this.getRoot().find('img.dropbackground');\n    };\n\n    /**\n     * Get drag home for a given choice.\n     *\n     * @param {int} group the group.\n     * @param {int} choice the choice number.\n     * @returns {jQuery} containing that div.\n     */\n    DragDropOntoImageQuestion.prototype.getDragHome = function(group, choice) {\n        if (!this.getRoot().find('.draghome.dragplaceholder.group' + group + '.choice' + choice).is(':visible')) {\n            return this.getRoot().find('.dragitemgroup' + group +\n                ' .draghome.infinite' +\n                '.choice' + choice +\n                '.group' + group);\n        }\n        return this.getRoot().find('.draghome.dragplaceholder.group' + group + '.choice' + choice);\n    };\n\n    /**\n     * Get an unplaced choice for a particular group.\n     *\n     * @param {int} group the group.\n     * @param {int} choice the choice number.\n     * @returns {jQuery} jQuery wrapping the unplaced choice. If there isn't one, the jQuery will be empty.\n     */\n    DragDropOntoImageQuestion.prototype.getUnplacedChoice = function(group, choice) {\n        return this.getRoot().find('.ddarea .draghome.group' + group + '.choice' + choice + '.unplaced').slice(0, 1);\n    };\n\n    /**\n     * Get the drag that is currently in a given place.\n     *\n     * @param {int} place the place number.\n     * @return {jQuery} the current drag (or an empty jQuery if none).\n     */\n    DragDropOntoImageQuestion.prototype.getCurrentDragInPlace = function(place) {\n        return this.getRoot().find('.ddarea .draghome.inplace' + place);\n    };\n\n    /**\n     * Return the number of blanks in a given group.\n     *\n     * @param {int} group the group number.\n     * @returns {int} the number of drops.\n     */\n    DragDropOntoImageQuestion.prototype.noOfDropsInGroup = function(group) {\n        return this.getRoot().find('.dropzone.group' + group).length;\n    };\n\n    /**\n     * Return the number of choices in a given group.\n     *\n     * @param {int} group the group number.\n     * @returns {int} the number of choices.\n     */\n    DragDropOntoImageQuestion.prototype.noOfChoicesInGroup = function(group) {\n        return this.getRoot().find('.dragitemgroup' + group + ' .draghome').length;\n    };\n\n    /**\n     * Return the number at the end of the CSS class name with the given prefix.\n     *\n     * @param {jQuery} node\n     * @param {String} prefix name prefix\n     * @returns {Number|null} the suffix if found, else null.\n     */\n    DragDropOntoImageQuestion.prototype.getClassnameNumericSuffix = function(node, prefix) {\n        var classes = node.attr('class');\n        if (classes !== '') {\n            var classesArr = classes.split(' ');\n            for (var index = 0; index < classesArr.length; index++) {\n                var patt1 = new RegExp('^' + prefix + '([0-9])+$');\n                if (patt1.test(classesArr[index])) {\n                    var patt2 = new RegExp('([0-9])+$');\n                    var match = patt2.exec(classesArr[index]);\n                    return Number(match[0]);\n                }\n            }\n        }\n        return null;\n    };\n\n    /**\n     * Get the choice number of a drag.\n     *\n     * @param {jQuery} drag the drag.\n     * @returns {Number} the choice number.\n     */\n    DragDropOntoImageQuestion.prototype.getChoice = function(drag) {\n        return this.getClassnameNumericSuffix(drag, 'choice');\n    };\n\n    /**\n     * Given a DOM node that is significant to this question\n     * (drag, drop, ...) get the group it belongs to.\n     *\n     * @param {jQuery} node a DOM node.\n     * @returns {Number} the group it belongs to.\n     */\n    DragDropOntoImageQuestion.prototype.getGroup = function(node) {\n        return this.getClassnameNumericSuffix(node, 'group');\n    };\n\n    /**\n     * Get the place number of a drop, or its corresponding hidden input.\n     *\n     * @param {jQuery} node the DOM node.\n     * @returns {Number} the place number.\n     */\n    DragDropOntoImageQuestion.prototype.getPlace = function(node) {\n        return this.getClassnameNumericSuffix(node, 'place');\n    };\n\n    /**\n     * Get drag clone for a given drag.\n     *\n     * @param {jQuery} drag the drag.\n     * @returns {jQuery} the drag's clone.\n     */\n    DragDropOntoImageQuestion.prototype.getDragClone = function(drag) {\n        return this.getRoot().find('.dragitemgroup' +\n            this.getGroup(drag) +\n            ' .draghome' +\n            '.choice' + this.getChoice(drag) +\n            '.group' + this.getGroup(drag) +\n            '.dragplaceholder');\n    };\n\n    /**\n     * Get infinite drag clones for given drag.\n     *\n     * @param {jQuery} drag the drag.\n     * @param {Boolean} inHome in the home area or not.\n     * @returns {jQuery} the drag's clones.\n     */\n    DragDropOntoImageQuestion.prototype.getInfiniteDragClones = function(drag, inHome) {\n        if (inHome) {\n            return this.getRoot().find('.dragitemgroup' +\n                this.getGroup(drag) +\n                ' .draghome' +\n                '.choice' + this.getChoice(drag) +\n                '.group' + this.getGroup(drag) +\n                '.infinite').not('.dragplaceholder');\n        }\n        return this.getRoot().find('.draghome' +\n            '.choice' + this.getChoice(drag) +\n            '.group' + this.getGroup(drag) +\n            '.infinite').not('.dragplaceholder');\n    };\n\n    /**\n     * Get drop for a given drag and place.\n     *\n     * @param {jQuery} drag the drag.\n     * @param {Integer} currentPlace the current place of drag.\n     * @returns {jQuery} the drop's clone.\n     */\n    DragDropOntoImageQuestion.prototype.getDrop = function(drag, currentPlace) {\n        return this.getRoot().find('.dropzone.group' + this.getGroup(drag) + '.place' + currentPlace);\n    };\n\n    /**\n     * Handle when the window is resized.\n     */\n    DragDropOntoImageQuestion.prototype.handleResize = function() {\n        var thisQ = this,\n            bgRatio = this.bgRatio();\n        if (this.isPrinting) {\n            bgRatio = 1;\n        }\n\n        this.getRoot().find('.ddarea .dropzone').each(function(i, dropNode) {\n            $(dropNode)\n                .css('left', parseInt($(dropNode).data('originX')) * parseFloat(bgRatio))\n                .css('top', parseInt($(dropNode).data('originY')) * parseFloat(bgRatio));\n            thisQ.handleElementScale(dropNode, 'left top');\n        });\n\n        this.getRoot().find('div.droparea .draghome').not('.beingdragged').each(function(key, drag) {\n            $(drag)\n                .css('left', parseFloat($(drag).data('originX')) * parseFloat(bgRatio))\n                .css('top', parseFloat($(drag).data('originY')) * parseFloat(bgRatio));\n            thisQ.handleElementScale(drag, 'left top');\n        });\n    };\n\n    /**\n     * Return the background ratio.\n     *\n     * @returns {number} Background ratio.\n     */\n    DragDropOntoImageQuestion.prototype.bgRatio = function() {\n        var bgImg = this.bgImage();\n        var bgImgNaturalWidth = bgImg.get(0).naturalWidth;\n        var bgImgClientWidth = bgImg.width();\n\n        return bgImgClientWidth / bgImgNaturalWidth;\n    };\n\n    /**\n     * Scale the drag if needed.\n     *\n     * @param {jQuery} element the item to place.\n     * @param {String} type scaling type\n     */\n    DragDropOntoImageQuestion.prototype.handleElementScale = function(element, type) {\n        var bgRatio = parseFloat(this.bgRatio());\n        if (this.isPrinting) {\n            bgRatio = 1;\n        }\n        $(element).css({\n            '-webkit-transform': 'scale(' + bgRatio + ')',\n            '-moz-transform': 'scale(' + bgRatio + ')',\n            '-ms-transform': 'scale(' + bgRatio + ')',\n            '-o-transform': 'scale(' + bgRatio + ')',\n            'transform': 'scale(' + bgRatio + ')',\n            'transform-origin': type\n        });\n    };\n\n    /**\n     * Calculate z-index value.\n     *\n     * @returns {number} z-index value\n     */\n    DragDropOntoImageQuestion.prototype.calculateZIndex = function() {\n        var zIndex = 0;\n        this.getRoot().find('.ddarea .dropzone, div.droparea .draghome').each(function(i, dropNode) {\n            dropNode = $(dropNode);\n            // Note that webkit browsers won't return the z-index value from the CSS stylesheet\n            // if the element doesn't have a position specified. Instead it'll return \"auto\".\n            var itemZIndex = dropNode.css('z-index') ? parseInt(dropNode.css('z-index')) : 0;\n\n            if (itemZIndex > zIndex) {\n                zIndex = itemZIndex;\n            }\n        });\n\n        return zIndex;\n    };\n\n    /**\n     * Check that the drag is drop to it's clone.\n     *\n     * @param {jQuery} drag The drag.\n     * @param {jQuery} drop The drop.\n     * @returns {boolean}\n     */\n    DragDropOntoImageQuestion.prototype.isDragSameAsDrop = function(drag, drop) {\n        return this.getChoice(drag) === this.getChoice(drop) && this.getGroup(drag) === this.getGroup(drop);\n    };\n\n    /**\n     * Singleton object that handles all the DragDropOntoImageQuestions\n     * on the page, and deals with event dispatching.\n     * @type {Object}\n     */\n    var questionManager = {\n\n        /**\n         * {boolean} ensures that the event handlers are only initialised once per page.\n         */\n        eventHandlersInitialised: false,\n\n        /**\n         * {Object} ensures that the drag event handlers are only initialised once per question,\n         * indexed by containerId (id on the .que div).\n         */\n        dragEventHandlersInitialised: {},\n\n        /**\n         * {boolean} is printing or not.\n         */\n        isPrinting: false,\n\n        /**\n         * {boolean} is keyboard navigation or not.\n         */\n        isKeyboardNavigation: false,\n\n        /**\n         * {Object} all the questions on this page, indexed by containerId (id on the .que div).\n         */\n        questions: {}, // An object containing all the information about each question on the page.\n\n        /**\n         * Initialise one question.\n         *\n         * @method\n         * @param {String} containerId the id of the div.que that contains this question.\n         * @param {boolean} readOnly whether the question is read-only.\n         * @param {Array} places data.\n         */\n        init: function(containerId, readOnly, places) {\n            questionManager.questions[containerId] =\n                new DragDropOntoImageQuestion(containerId, readOnly, places);\n            if (!questionManager.eventHandlersInitialised) {\n                questionManager.setupEventHandlers();\n                questionManager.eventHandlersInitialised = true;\n            }\n            if (!questionManager.dragEventHandlersInitialised.hasOwnProperty(containerId)) {\n                questionManager.dragEventHandlersInitialised[containerId] = true;\n                // We do not use the body event here to prevent the other event on Mobile device, such as scroll event.\n                var questionContainer = document.getElementById(containerId);\n                if (questionContainer.classList.contains('ddimageortext') &&\n                    !questionContainer.classList.contains('qtype_ddimageortext-readonly')) {\n                    // TODO: Convert all the jQuery selectors and events to native Javascript.\n                    questionManager.addEventHandlersToDrag($(questionContainer).find('.draghome'));\n                }\n            }\n        },\n\n        /**\n         * Set up the event handlers that make this question type work. (Done once per page.)\n         */\n        setupEventHandlers: function() {\n            $('body')\n                .on('keydown',\n                    '.que.ddimageortext:not(.qtype_ddimageortext-readonly) .dropzones .dropzone',\n                    questionManager.handleKeyPress)\n                .on('keydown',\n                    '.que.ddimageortext:not(.qtype_ddimageortext-readonly) .draghome.placed:not(.beingdragged)',\n                    questionManager.handleKeyPress)\n                .on('qtype_ddimageortext-dragmoved', questionManager.handleDragMoved);\n            $(window).on('resize', function() {\n                questionManager.handleWindowResize(false);\n            });\n            window.addEventListener('beforeprint', function() {\n                questionManager.isPrinting = true;\n                questionManager.handleWindowResize(questionManager.isPrinting);\n            });\n            window.addEventListener('afterprint', function() {\n                questionManager.isPrinting = false;\n                questionManager.handleWindowResize(questionManager.isPrinting);\n            });\n            setTimeout(function() {\n                questionManager.fixLayoutIfThingsMoved();\n            }, 100);\n        },\n\n        /**\n         * Binding the drag/touch event again for newly created element.\n         *\n         * @param {jQuery} element Element to bind the event\n         */\n        addEventHandlersToDrag: function(element) {\n            // Unbind all the mousedown and touchstart events to prevent double binding.\n            element.unbind('mousedown touchstart');\n            element.on('mousedown touchstart', questionManager.handleDragStart);\n        },\n\n        /**\n         * Handle mouse down / touch start events on drags.\n         * @param {Event} e the DOM event.\n         */\n        handleDragStart: function(e) {\n            e.preventDefault();\n            var question = questionManager.getQuestionForEvent(e);\n            if (question) {\n                question.handleDragStart(e);\n            }\n        },\n\n        /**\n         * Handle key down / press events on drags.\n         * @param {KeyboardEvent} e\n         */\n        handleKeyPress: function(e) {\n            if (questionManager.isKeyboardNavigation) {\n                return;\n            }\n            questionManager.isKeyboardNavigation = true;\n            var question = questionManager.getQuestionForEvent(e);\n            if (question) {\n                question.handleKeyPress(e);\n            }\n        },\n\n        /**\n         * Handle when the window is resized.\n         * @param {boolean} isPrinting\n         */\n        handleWindowResize: function(isPrinting) {\n            for (var containerId in questionManager.questions) {\n                if (questionManager.questions.hasOwnProperty(containerId)) {\n                    questionManager.questions[containerId].isPrinting = isPrinting;\n                    questionManager.questions[containerId].handleResize();\n                }\n            }\n        },\n\n        /**\n         * Sometimes, despite our best efforts, things change in a way that cannot\n         * be specifically caught (e.g. dock expanding or collapsing in Boost).\n         * Therefore, we need to periodically check everything is in the right position.\n         */\n        fixLayoutIfThingsMoved: function() {\n            this.handleWindowResize(questionManager.isPrinting);\n            // We use setTimeout after finishing work, rather than setInterval,\n            // in case positioning things is slow. We want 100 ms gap\n            // between executions, not what setInterval does.\n            setTimeout(function() {\n                questionManager.fixLayoutIfThingsMoved(questionManager.isPrinting);\n            }, 100);\n        },\n\n        /**\n         * Handle when drag moved.\n         *\n         * @param {Event} e the event.\n         * @param {jQuery} drag the drag\n         * @param {jQuery} target the target\n         * @param {DragDropOntoImageQuestion} thisQ the question.\n         */\n        handleDragMoved: function(e, drag, target, thisQ) {\n            drag.removeClass('beingdragged').css('z-index', '');\n            drag.css('top', target.position().top).css('left', target.position().left);\n            target.after(drag);\n            target.removeClass('active');\n            if (typeof drag.data('unplaced') !== 'undefined' && drag.data('unplaced') === true) {\n                drag.removeClass('placed').addClass('unplaced');\n                drag.removeAttr('tabindex');\n                drag.removeData('unplaced');\n                drag.css('top', '')\n                    .css('left', '')\n                    .css('transform', '');\n                if (drag.hasClass('infinite') && thisQ.getInfiniteDragClones(drag, true).length > 1) {\n                    thisQ.getInfiniteDragClones(drag, true).first().remove();\n                }\n            } else {\n                drag.data('originX', target.data('originX')).data('originY', target.data('originY'));\n                thisQ.handleElementScale(drag, 'left top');\n            }\n            if (typeof drag.data('isfocus') !== 'undefined' && drag.data('isfocus') === true) {\n                drag.focus();\n                drag.removeData('isfocus');\n            }\n            if (typeof target.data('isfocus') !== 'undefined' && target.data('isfocus') === true) {\n                target.removeData('isfocus');\n            }\n            if (questionManager.isKeyboardNavigation) {\n                questionManager.isKeyboardNavigation = false;\n            }\n        },\n\n        /**\n         * Given an event, work out which question it effects.\n         * @param {Event} e the event.\n         * @returns {DragDropOntoImageQuestion|undefined} The question, or undefined.\n         */\n        getQuestionForEvent: function(e) {\n            var containerId = $(e.currentTarget).closest('.que.ddimageortext').attr('id');\n            return questionManager.questions[containerId];\n        }\n    };\n\n    /**\n     * @alias module:qtype_ddimageortext/question\n     */\n    return {\n        init: questionManager.init\n    };\n});\n"],"file":"question.min.js"}