Proyectos de Subversion Moodle

Rev

Autoría | Ultima modificación | Ver Log |

{"version":3,"file":"form.min.js","sources":["../src/form.js"],"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 * This class provides the enhancements to the drag-drop marker editing form.\n *\n * @module     qtype_ddmarker/form\n * @copyright  2018 The Open University\n * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\ndefine(['jquery', 'core/dragdrop', 'qtype_ddmarker/shapes'], function($, dragDrop, Shapes) {\n\n    \"use strict\";\n\n    /**\n     * Create the manager object that deals with keeping everything synchronised for one drop zone.\n     *\n     * @param {int} dropzoneNo the index of this drop zone in the form. 0, 1, ....\n     * @constructor\n     */\n    function DropZoneManager(dropzoneNo) {\n        this.dropzoneNo = dropzoneNo;\n        this.svgEl = null;\n\n        this.shape = Shapes.make(this.getShapeType(), this.getLabel());\n        this.updateCoordinatesFromForm();\n    }\n\n    /**\n     * Update the coordinates from a particular string.\n     *\n     * @param {SVGElement} [svg] the SVG element that is the preview.\n     */\n    DropZoneManager.prototype.updateCoordinatesFromForm = function(svg) {\n        var coordinates = this.getCoordinates(),\n            currentNumPoints = this.shape.getType() === 'polygon' && this.shape.points.length;\n        if (this.shape.getCoordinates() === coordinates) {\n            return;\n        }\n        // We don't need to scale the shape for editing form.\n        if (!this.shape.parse(coordinates, 1)) {\n            // Invalid coordinates. Don't update the preview.\n            return;\n        }\n\n        if (this.shape.getType() === 'polygon' && currentNumPoints !== this.shape.points.length) {\n            // Polygon, and size has changed.\n            var currentyActive = this.isActive();\n            this.removeFromSvg();\n            if (svg) {\n                this.addToSvg(svg);\n                if (currentyActive) {\n                    this.setActive();\n                }\n            }\n        } else {\n            // Simple update.\n            this.updateSvgEl();\n        }\n        // Update the rounded coordinates if needed.\n        this.setCoordinatesInForm();\n    };\n\n    /**\n     * Update the label.\n     */\n    DropZoneManager.prototype.updateLabel = function() {\n        var label = this.getLabel();\n        if (this.shape.label !== label) {\n            this.shape.label = label;\n            this.updateSvgEl();\n        }\n    };\n\n    /**\n     * Handle if the type of shape has changed.\n     *\n     * @param {SVGElement} [svg] an SVG element to add this new shape to.\n     */\n    DropZoneManager.prototype.changeShape = function(svg) {\n        var newShapeType = this.getShapeType(),\n            currentyActive = this.isActive();\n\n        if (newShapeType === this.shape.getType()) {\n            return;\n        }\n\n        // It has really changed.\n        this.removeFromSvg();\n        this.shape = Shapes.getSimilar(newShapeType, this.shape);\n        if (svg) {\n            this.addToSvg(svg);\n            if (currentyActive) {\n                this.setActive();\n            }\n        }\n        this.setCoordinatesInForm();\n    };\n\n    /**\n     * Add this drop zone to an SVG graphic.\n     *\n     * @param {SVGElement} svg the SVG image to which to add this drop zone.\n     */\n    DropZoneManager.prototype.addToSvg = function(svg) {\n        if (this.svgEl !== null) {\n            throw new Error('this.svgEl already set');\n        }\n        this.svgEl = this.shape.makeSvg(svg);\n        if (!this.svgEl) {\n            return;\n        }\n        this.svgEl.setAttribute('class', 'dropzone');\n        this.svgEl.setAttribute('data-dropzone-no', this.dropzoneNo);\n\n        // Add handles.\n        var handles = this.shape.getHandlePositions();\n        if (handles === null) {\n            return;\n        }\n\n        var moveHandle = Shapes.createSvgElement(this.svgEl, 'circle');\n        moveHandle.setAttribute('cx', handles.moveHandle.x);\n        moveHandle.setAttribute('cy', handles.moveHandle.y);\n        moveHandle.setAttribute('r', 7);\n        moveHandle.setAttribute('class', 'handle move');\n\n        for (var i = 0; i < handles.editHandles.length; ++i) {\n            this.makeEditHandle(i, handles.editHandles[i]);\n        }\n    };\n\n    /**\n     * Add a new edit handle.\n     *\n     * @param {int} index the handle index.\n     * @param {Point} point the point at which to add the handle.\n     */\n    DropZoneManager.prototype.makeEditHandle = function(index, point) {\n        var editHandle = Shapes.createSvgElement(this.svgEl, 'rect');\n        editHandle.setAttribute('x', point.x - 6);\n        editHandle.setAttribute('y', point.y - 6);\n        editHandle.setAttribute('width', 11);\n        editHandle.setAttribute('height', 11);\n        editHandle.setAttribute('class', 'handle edit');\n        editHandle.setAttribute('data-edit-handle-no', index);\n    };\n\n    /**\n     * Remove this drop zone from an SVG image.\n     */\n    DropZoneManager.prototype.removeFromSvg = function() {\n        if (this.svgEl !== null) {\n            this.svgEl.parentNode.removeChild(this.svgEl);\n            this.svgEl = null;\n        }\n    };\n\n    /**\n     * Update the shape of this drop zone (but not type) in an SVG image.\n     */\n    DropZoneManager.prototype.updateSvgEl = function() {\n        if (this.svgEl === null) {\n            return;\n        }\n\n        this.shape.updateSvg(this.svgEl);\n\n        // Adjust handles.\n        var handles = this.shape.getHandlePositions();\n        if (handles === null) {\n            return;\n        }\n\n        // Move handle.\n        // The shape + its label are the first two children of svgEl.\n        // Then come the move handle followed by the edit handles.\n        this.svgEl.childNodes[2].setAttribute('cx', handles.moveHandle.x);\n        this.svgEl.childNodes[2].setAttribute('cy', handles.moveHandle.y);\n\n        // Edit handles.\n        for (var i = 0; i < handles.editHandles.length; ++i) {\n            this.svgEl.childNodes[3 + i].setAttribute('x', handles.editHandles[i].x - 6);\n            this.svgEl.childNodes[3 + i].setAttribute('y', handles.editHandles[i].y - 6);\n        }\n    };\n\n    /**\n     * Find out of this drop zone is currently being edited.\n     *\n     * @return {boolean} true if it is.\n     */\n    DropZoneManager.prototype.isActive = function() {\n        return this.svgEl !== null && this.svgEl.getAttribute('class').match(/\\bactive\\b/);\n    };\n\n    /**\n     * Set this drop zone as being edited.\n     */\n    DropZoneManager.prototype.setActive = function() {\n        // Move this one to last, so that it is always on top.\n        // (Otherwise the handles may not be able to receive events.)\n        var parent = this.svgEl.parentNode;\n        parent.removeChild(this.svgEl);\n        parent.appendChild(this.svgEl);\n        this.svgEl.setAttribute('class', this.svgEl.getAttribute('class') + ' active');\n    };\n\n    /**\n     * Set the coordinates in the form to match the current shape.\n     */\n    DropZoneManager.prototype.setCoordinatesInForm = function() {\n        dragDropForm.form.setFormValue('drops', [this.dropzoneNo, 'coords'], this.shape.getCoordinates());\n    };\n\n    /**\n     * Returns the coordinates for a drop zone from the text input in the form.\n     * @returns {string} the coordinates.\n     */\n    DropZoneManager.prototype.getCoordinates = function() {\n        return dragDropForm.form.getFormValue('drops', [this.dropzoneNo, 'coords']).replace(/\\s*/g, '');\n    };\n\n    /**\n     * Returns the selected marker number from the dropdown in the form.\n     * @returns {int} choice number.\n     */\n    DropZoneManager.prototype.getChoiceNo = function() {\n        return dragDropForm.form.getFormValue('drops', [this.dropzoneNo, 'choice']);\n    };\n\n    /**\n     * Returns the selected marker number from the dropdown in the form.\n     * @returns {String} marker label text.\n     */\n    DropZoneManager.prototype.getLabel = function() {\n        return dragDropForm.form.getMarkerText(this.getChoiceNo());\n    };\n\n\n    /**\n     * Returns the selected type of shape in the form.\n     * @returns {String} 'circle', 'rectangle' or 'polygon'.\n     */\n    DropZoneManager.prototype.getShapeType = function() {\n        return dragDropForm.form.getFormValue('drops', [this.dropzoneNo, 'shape']);\n    };\n\n    /**\n     * Start responding to dragging the move handle.\n     * @param {Event} e Event object\n     */\n    DropZoneManager.prototype.handleMove = function(e) {\n        var info = dragDrop.prepare(e);\n        if (!info.start) {\n            return;\n        }\n\n        var movingDropZone = this,\n                lastX = info.x,\n                lastY = info.y,\n                dragProxy = this.makeDragProxy(info.x, info.y),\n                bgImg = $('fieldset#id_previewareaheader .dropbackground'),\n                maxX = bgImg.width(),\n                maxY = bgImg.height();\n\n        dragDrop.start(e, $(dragProxy), function(pageX, pageY) {\n            movingDropZone.shape.move(pageX - lastX, pageY - lastY, maxX, maxY);\n            lastX = pageX;\n            lastY = pageY;\n            movingDropZone.updateSvgEl();\n            movingDropZone.setCoordinatesInForm();\n        }, function() {\n            document.body.removeChild(dragProxy);\n        });\n    };\n\n    /**\n     * Start responding to dragging the move handle.\n     * @param {Event} e Event object\n     * @param {int} handleIndex\n     * @param {SVGElement} [svg] an SVG element to add this new shape to.\n     */\n    DropZoneManager.prototype.handleEdit = function(e, handleIndex, svg) {\n        var info = dragDrop.prepare(e);\n        if (!info.start) {\n            return;\n        }\n\n        // For polygons, CTRL + drag adds a new point.\n        if (this.shape.getType() === 'polygon' && (e.ctrlKey || e.metaKey)) {\n            this.shape.addNewPointAfter(handleIndex);\n            this.removeFromSvg();\n            this.addToSvg(svg);\n            this.setActive();\n        }\n\n        var changingDropZone = this,\n            lastX = info.x,\n            lastY = info.y,\n            dragProxy = this.makeDragProxy(info.x, info.y),\n            bgImg = $('fieldset#id_previewareaheader .dropbackground'),\n            maxX = bgImg.width(),\n            maxY = bgImg.height();\n\n        dragDrop.start(e, $(dragProxy), function(pageX, pageY) {\n            changingDropZone.shape.edit(handleIndex, pageX - lastX, pageY - lastY, maxX, maxY);\n            lastX = pageX;\n            lastY = pageY;\n            changingDropZone.updateSvgEl();\n            changingDropZone.setCoordinatesInForm();\n        }, function() {\n            document.body.removeChild(dragProxy);\n            changingDropZone.shape.normalizeShape();\n            changingDropZone.updateSvgEl();\n            changingDropZone.setCoordinatesInForm();\n        });\n    };\n\n    /**\n     * Make an invisible drag proxy.\n     *\n     * @param {int} x x position .\n     * @param {int} y y position.\n     * @returns {HTMLElement} the drag proxy.\n     */\n    DropZoneManager.prototype.makeDragProxy = function(x, y) {\n        var dragProxy = document.createElement('div');\n        dragProxy.style.position = 'absolute';\n        dragProxy.style.top = y + 'px';\n        dragProxy.style.left = x + 'px';\n        dragProxy.style.width = '1px';\n        dragProxy.style.height = '1px';\n        document.body.appendChild(dragProxy);\n        return dragProxy;\n    };\n\n    /**\n     * Singleton object for managing all the parts of the form.\n     */\n    var dragDropForm = {\n\n        /**\n         * @var {object} for interacting with the file pickers.\n         */\n        fp: null, // Object containing functions associated with the file picker.\n\n        /**\n         * @var {int} the number of drop-zones on the form.\n         */\n        noDropZones: null,\n\n        /**\n         * @var {DropZoneManager[]} the drop zones in the preview, indexed by drop zone number.\n         */\n        dropZones: [],\n\n        /**\n         * Initialise the form.\n         */\n        init: function() {\n            dragDropForm.fp = dragDropForm.filePickers();\n            dragDropForm.noDropZones = dragDropForm.form.getFormValue('nodropzone', []);\n            dragDropForm.setOptionsForDragItemSelectors();\n            dragDropForm.createShapes();\n            dragDropForm.setupEventHandlers();\n            dragDropForm.waitForFilePickerToInitialise();\n        },\n\n        /**\n         * Add html for the preview area.\n         */\n        setupPreviewArea: function() {\n            $('fieldset#id_previewareaheader div.fcontainer').append(\n                '<div class=\"ddarea que ddmarker\">' +\n                '   <div id=\"ddm-droparea\" class=\"droparea\">' +\n                '       <img class=\"dropbackground\" />' +\n                '       <div id=\"ddm-dropzone\" class=\"dropzones\">' +\n                '       </div>' +\n                '   </div>' +\n                '</div>');\n        },\n\n        /**\n         * When a new marker is added this function updates the Marker dropdown controls in Drop zones.\n         */\n        setOptionsForDragItemSelectors: function() {\n            var dragItemsOptions = {'0': ''};\n            var noItems = dragDropForm.form.getFormValue('noitems', []);\n            var selectedValues = [];\n            var selector;\n            var i, label;\n            for (i = 1; i <= noItems; i++) {\n                label = dragDropForm.form.getMarkerText(i);\n                if (label !== \"\") {\n                    // HTML escape the label.\n                    dragItemsOptions[i] = $('<div/>').text(label).html();\n                }\n            }\n            // Get all the currently selected drags for each drop.\n            for (i = 0; i < dragDropForm.noDropZones; i++) {\n                selector = $('#id_drops_' + i + '_choice');\n                selectedValues[i] = Number(selector.val());\n            }\n            for (i = 0; i < dragDropForm.noDropZones; i++) {\n                selector = $('#id_drops_' + i + '_choice');\n                // Remove all options for drag choice.\n                selector.find('option').remove();\n                // And recreate the options.\n                for (var value in dragItemsOptions) {\n                    value = Number(value);\n                    var option = '<option value=\"' + value + '\">' + dragItemsOptions[value] + '</option>';\n                    selector.append(option);\n                    var optionnode = selector.find('option[value=\"' + value + '\"]');\n\n\n                    if (value === 0) {\n                        continue; // The 'no item' option is always selectable.\n                    }\n\n                    // Is this the currently selected value?\n                    if (value === selectedValues[i]) {\n                        optionnode.attr('selected', true);\n                        continue; // If it s selected, we must leave it enabled.\n                    }\n\n                    // Count how many times it is used, and if necessary, disable.\n                    var noofdrags = dragDropForm.form.getFormValue('drags', [value - 1, 'noofdrags']);\n                    if (Number(noofdrags) === 0) { // 'noofdrags === 0' means infinite.\n                        continue; // Nothing to check.\n                    }\n\n                    // Go through all selected values in drop downs.\n                    for (var k in selectedValues) {\n                        if (Number(selectedValues[k]) !== value) {\n                            continue;\n                        }\n\n                        // Count down 'noofdrags' and if reach zero then set disabled option for this drag item.\n                        if (Number(noofdrags) === 1) {\n                            optionnode.attr('disabled', true);\n                            break;\n                        } else {\n                            noofdrags--;\n                        }\n                    }\n                }\n\n                if (dragDropForm.dropZones.length > 0) {\n                    dragDropForm.dropZones[i].updateLabel();\n                }\n            }\n        },\n\n        /**\n         * Create the shape representation of each dropZone.\n         */\n        createShapes: function() {\n            for (var dropzoneNo = 0; dropzoneNo < dragDropForm.noDropZones; dropzoneNo++) {\n                dragDropForm.dropZones[dropzoneNo] = new DropZoneManager(dropzoneNo);\n            }\n        },\n\n        /**\n         * Events linked to form actions.\n         */\n        setupEventHandlers: function() {\n            // Changes to labels in the Markers section.\n            $('fieldset#id_draggableitemheader').on('change input', 'input, select', function() {\n                dragDropForm.setOptionsForDragItemSelectors();\n            });\n\n            // Changes to Drop zones section: shape, coordinates and marker.\n            $('fieldset#id_dropzoneheader').on('change input', 'input, select', function(e) {\n                var ids = e.currentTarget.name.match(/^drops\\[(\\d+)]\\[([a-z]*)]$/);\n                if (!ids) {\n                    return;\n                }\n\n                var dropzoneNo = ids[1],\n                    inputType = ids[2],\n                    dropZone = dragDropForm.dropZones[dropzoneNo];\n\n                switch (inputType) {\n                    case 'shape':\n                        dropZone.changeShape(dragDropForm.form.getSvg());\n                        break;\n\n                    case 'coords':\n                        dropZone.updateCoordinatesFromForm(dragDropForm.form.getSvg());\n                        break;\n\n                    case 'choice':\n                        dropZone.updateLabel();\n                        break;\n                }\n            });\n\n            // Click to toggle graphical editing.\n            var previewArea = $('fieldset#id_previewareaheader');\n            previewArea.on('click', 'g.dropzone', function(e) {\n                var dropzoneNo = $(e.currentTarget).data('dropzone-no'),\n                    currentlyActive = dragDropForm.dropZones[dropzoneNo].isActive();\n\n                $(dragDropForm.form.getSvg()).find('.dropzone.active').removeClass('active');\n\n                if (!currentlyActive) {\n                    dragDropForm.dropZones[dropzoneNo].setActive();\n                }\n            });\n\n            // Drag start on a move handle.\n            previewArea.on('mousedown touchstart', '.dropzone .handle.move', function(e) {\n                var dropzoneNo = $(e.currentTarget).closest('g').data('dropzoneNo');\n\n                dragDropForm.dropZones[dropzoneNo].handleMove(e);\n            });\n\n            // Drag start on a move handle.\n            previewArea.on('mousedown touchstart', '.dropzone .handle.edit', function(e) {\n                var dropzoneNo = $(e.currentTarget).closest('g').data('dropzoneNo'),\n                    handleIndex = e.currentTarget.getAttribute('data-edit-handle-no');\n\n                dragDropForm.dropZones[dropzoneNo].handleEdit(e, handleIndex, dragDropForm.form.getSvg());\n            });\n        },\n\n        /**\n         * Prevents adding drop zones until the preview background image is ready to load.\n         */\n        waitForFilePickerToInitialise: function() {\n            if (dragDropForm.fp.file('bgimage').href === null) {\n                // It would be better to use an onload or onchange event rather than this timeout.\n                // Unfortunately attempts to do this early are overwritten by filepicker during its loading.\n                setTimeout(dragDropForm.waitForFilePickerToInitialise, 1000);\n                return;\n            }\n\n            // From now on, when a new file gets loaded into the filepicker, update the preview.\n            // This is not in the setupEventHandlers section as it needs to be delayed until\n            // after filepicker's javascript has finished.\n            $('form.mform[data-qtype=\"ddmarker\"]').on('change', '#id_bgimage', dragDropForm.loadPreviewImage);\n\n            if ($('#ddm-droparea').length) {\n                dragDropForm.loadPreviewImage();\n            } else {\n                // Setup preview area when the background image is uploaded the first time.\n                dragDropForm.setupPreviewArea();\n                dragDropForm.loadPreviewImage();\n            }\n        },\n\n        /**\n         * Loads the preview background image.\n         */\n        loadPreviewImage: function() {\n            $('fieldset#id_previewareaheader .dropbackground')\n                    .one('load', dragDropForm.afterPreviewImageLoaded)\n                    .attr('src', dragDropForm.fp.file('bgimage').href);\n        },\n\n        /**\n         * Functions to run after background image loaded.\n         */\n        afterPreviewImageLoaded: function() {\n            var bgImg = $('fieldset#id_previewareaheader .dropbackground');\n            // Place the dropzone area over the background image (adding one to account for the border).\n            $('#ddm-dropzone').css('position', 'relative').css('top', (bgImg.height() + 1) * -1);\n            $('#ddm-droparea').css('height', bgImg.height() + 20);\n            dragDropForm.updateSvgDisplay();\n        },\n\n        /**\n         * Draws or re-draws all dropzones in the preview area based on form data.\n         * Call this function when there is a change in the form data.\n         */\n        updateSvgDisplay: function() {\n            var bgImg = $('fieldset#id_previewareaheader .dropbackground'),\n                dropzoneNo;\n\n            if (dragDropForm.form.getSvg()) {\n                // Already exists, just need to be updated.\n                for (dropzoneNo = 0; dropzoneNo < dragDropForm.noDropZones; dropzoneNo++) {\n                    dragDropForm.dropZones[dropzoneNo].updateSvgEl();\n                }\n\n            } else {\n                // Create.\n                $('#ddm-dropzone').html('<svg xmlns=\"http://www.w3.org/2000/svg\" class=\"dropzones\" ' +\n                    'width=\"' + bgImg.outerWidth() + '\" ' +\n                    'height=\"' + bgImg.outerHeight() + '\"></svg>');\n                for (dropzoneNo = 0; dropzoneNo < dragDropForm.noDropZones; dropzoneNo++) {\n                    dragDropForm.dropZones[dropzoneNo].addToSvg(dragDropForm.form.getSvg());\n                }\n            }\n        },\n\n        /**\n         * Helper to make it easy to work with form elements with names like \"drops[0][shape]\".\n         */\n        form: {\n            /**\n             * Returns the label text for a marker.\n             * @param {int} markerNo\n             * @returns {string} Marker text\n             */\n            getMarkerText: function(markerNo) {\n                if (Number(markerNo) !== 0) {\n                    var label = dragDropForm.form.getFormValue('drags', [markerNo - 1, 'label']);\n                    return label.replace(new RegExp(\"^\\\\s*(.*)\\\\s*$\"), \"$1\");\n                } else {\n                    return '';\n                }\n            },\n\n            /**\n             * Get the SVG element, if there is one, otherwise return null.\n             *\n             * @returns {SVGElement|null} the SVG element or null.\n             */\n            getSvg: function() {\n                var svg = $('fieldset#id_previewareaheader svg');\n                if (svg.length === 0) {\n                    return null;\n                } else {\n                    return svg[0];\n                }\n            },\n\n            toNameWithIndex: function(name, indexes) {\n                var indexString = name;\n                for (var i = 0; i < indexes.length; i++) {\n                    indexString = indexString + '[' + indexes[i] + ']';\n                }\n                return indexString;\n            },\n\n            getEl: function(name, indexes) {\n                var form = $('form.mform[data-qtype=\"ddmarker\"]')[0];\n                return form.elements[this.toNameWithIndex(name, indexes)];\n            },\n\n            /**\n             * Helper to get the value of a form elements with name like \"drops[0][shape]\".\n             *\n             * @param {String} name the base name, e.g. 'drops'.\n             * @param {String[]} indexes the indexes, e.g. ['0', 'shape'].\n             * @return {String} the value of that field.\n             */\n            getFormValue: function(name, indexes) {\n                var el = this.getEl(name, indexes);\n                if (el.type === 'checkbox') {\n                    return el.checked;\n                } else {\n                    return el.value;\n                }\n            },\n\n            /**\n             * Helper to get the value of a form elements with name like \"drops[0][shape]\".\n             *\n             * @param {String} name the base name, e.g. 'drops'.\n             * @param {String[]} indexes the indexes, e.g. ['0', 'shape'].\n             * @param {String} value the value to set.\n             */\n            setFormValue: function(name, indexes, value) {\n                var el = this.getEl(name, indexes);\n                if (el.type === 'checkbox') {\n                    el.checked = value;\n                } else {\n                    el.value = value;\n                }\n            }\n        },\n\n        /**\n         * Utility to get the file name and url from the filepicker.\n         * @returns {Object} object containing functions {file, name}\n         */\n        filePickers: function() {\n            var draftItemIdsToName;\n            var nameToParentNode;\n            if (draftItemIdsToName === undefined) {\n                draftItemIdsToName = {};\n                nameToParentNode = {};\n                $('form.mform input.filepickerhidden').each(function(key, filepicker) {\n                    draftItemIdsToName[filepicker.value] = filepicker.name;\n                    nameToParentNode[filepicker.name] = filepicker.parentNode;\n                });\n            }\n            return {\n                file: function(name) {\n                    var fileAnchor = $(nameToParentNode[name]).find('div.filepicker-filelist a');\n                    if (fileAnchor.length) {\n                        return {href: fileAnchor.get(0).href, name: fileAnchor.get(0).innerHTML};\n                    } else {\n                        return {href: null, name: null};\n                    }\n                },\n                name: function(draftitemid) {\n                    return draftItemIdsToName[draftitemid];\n                }\n            };\n        }\n    };\n\n    /**\n     * @alias module:qtype_ddmarker/form\n     */\n    return {\n        /**\n         * Initialise the form javascript features.\n         * @param {Object} maxBgimageSize object with two properties: width and height.\n         */\n        init: dragDropForm.init\n    };\n});\n"],"names":["define","$","dragDrop","Shapes","DropZoneManager","dropzoneNo","svgEl","shape","make","this","getShapeType","getLabel","updateCoordinatesFromForm","prototype","svg","coordinates","getCoordinates","currentNumPoints","getType","points","length","parse","currentyActive","isActive","removeFromSvg","addToSvg","setActive","updateSvgEl","setCoordinatesInForm","updateLabel","label","changeShape","newShapeType","getSimilar","Error","makeSvg","setAttribute","handles","getHandlePositions","moveHandle","createSvgElement","x","y","i","editHandles","makeEditHandle","index","point","editHandle","parentNode","removeChild","updateSvg","childNodes","getAttribute","match","parent","appendChild","dragDropForm","form","setFormValue","getFormValue","replace","getChoiceNo","getMarkerText","handleMove","e","info","prepare","start","movingDropZone","lastX","lastY","dragProxy","makeDragProxy","bgImg","maxX","width","maxY","height","pageX","pageY","move","document","body","handleEdit","handleIndex","ctrlKey","metaKey","addNewPointAfter","changingDropZone","edit","normalizeShape","createElement","style","position","top","left","fp","noDropZones","dropZones","init","filePickers","setOptionsForDragItemSelectors","createShapes","setupEventHandlers","waitForFilePickerToInitialise","setupPreviewArea","append","selector","dragItemsOptions","noItems","selectedValues","text","html","Number","val","value","find","remove","option","optionnode","noofdrags","k","attr","on","ids","currentTarget","name","inputType","dropZone","getSvg","previewArea","data","currentlyActive","removeClass","closest","file","href","loadPreviewImage","setTimeout","one","afterPreviewImageLoaded","css","updateSvgDisplay","outerWidth","outerHeight","markerNo","RegExp","toNameWithIndex","indexes","indexString","getEl","elements","el","type","checked","draftItemIdsToName","nameToParentNode","undefined","each","key","filepicker","fileAnchor","get","innerHTML","draftitemid"],"mappings":"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"}