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 * JavaScript to allow dragging options to slots (using mouse down or touch) or tab through slots using keyboard.\n *\n * @module     qtype_ddimageortext/form\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'], function($, dragDrop) {\n\n    \"use strict\";\n\n    /**\n     * Singleton object to handle progressive enhancement of the\n     * drag-drop onto image question editing form.\n     * @type {Object}\n     */\n    var dragDropToImageForm = {\n        /**\n         * @var {Object} maxBgImageSize Properties width and height.\n         * @private\n         */\n        maxBgImageSize: null,\n\n        /**\n         * @var {Object} maxDragImageSize with properties width and height.\n         * @private\n         */\n        maxDragImageSize: null,\n\n        /**\n         * @property {object} fp for interacting with the file pickers.\n         * @private\n         */\n        fp: null, // Object containing functions associated with the file picker.\n\n        /**\n         * Initialise the form javascript features.\n         *\n         * @method\n         */\n        init: function() {\n            dragDropToImageForm.fp = dragDropToImageForm.filePickers();\n            dragDropToImageForm.updateVisibilityOfFilePickers();\n            dragDropToImageForm.setOptionsForDragItemSelectors();\n            dragDropToImageForm.setupEventHandlers();\n            dragDropToImageForm.waitForFilePickerToInitialise();\n        },\n\n        /**\n         * Add html for the preview area.\n         */\n        setupPreviewArea: function() {\n            $('#id_previewareaheader').append(\n                '<div class=\"ddarea que ddimageortext\">' +\n                '  <div id=\"id_droparea\" class=\"droparea\">' +\n                '    <img class=\"dropbackground\" />' +\n                '    <div class=\"dropzones\"></div>' +\n                '  </div>' +\n                '  <div class=\"dragitems\"></div>' +\n                '</div>');\n        },\n\n        /**\n         * Waits for the file-pickers to be sufficiently ready before initialising the preview.\n         */\n        waitForFilePickerToInitialise: function() {\n            if (dragDropToImageForm.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(dragDropToImageForm.waitForFilePickerToInitialise, 1000);\n                return;\n            }\n            M.util.js_pending('dragDropToImageForm');\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=\"ddimageortext\"]').on('change', '.filepickerhidden', function() {\n                M.util.js_pending('dragDropToImageForm');\n                dragDropToImageForm.loadPreviewImage();\n            });\n            if ($('#id_droparea').length) {\n                dragDropToImageForm.loadPreviewImage();\n            } else {\n                // Setup preview area when the background image is uploaded the first time.\n                dragDropToImageForm.setupPreviewArea();\n                dragDropToImageForm.loadPreviewImage();\n            }\n        },\n\n        /**\n         * Loads the preview background image.\n         */\n        loadPreviewImage: function() {\n            $('fieldset#id_previewareaheader .dropbackground')\n                .one('load', dragDropToImageForm.afterPreviewImageLoaded)\n                .attr('src', dragDropToImageForm.fp.file('bgimage').href);\n        },\n\n        /**\n         * After the background image is loaded, continue setting up the preview.\n         */\n        afterPreviewImageLoaded: function() {\n            dragDropToImageForm.createDropZones();\n            M.util.js_complete('dragDropToImageForm');\n        },\n\n        /**\n         * Create, or recreate all the drop zones.\n         */\n        createDropZones: function() {\n            var dropZoneHolder = $('.dropzones');\n            dropZoneHolder.empty();\n\n            var bgimageurl = dragDropToImageForm.fp.file('bgimage').href;\n            if (bgimageurl === null) {\n                return; // There is not currently a valid preview to update.\n            }\n\n            var numDrops = dragDropToImageForm.form.getFormValue('nodropzone', []);\n            for (var dropNo = 0; dropNo < numDrops; dropNo++) {\n                var dragNo = dragDropToImageForm.form.getFormValue('drops', [dropNo, 'choice']);\n                if (dragNo === '0') {\n                    continue;\n                }\n                dragNo = dragNo - 1;\n                var group = dragDropToImageForm.form.getFormValue('drags', [dragNo, 'draggroup']),\n                    label = dragDropToImageForm.form.getFormValue('draglabel', [dragNo]);\n                if ('image' === dragDropToImageForm.form.getFormValue('drags', [dragNo, 'dragitemtype'])) {\n                    var imgUrl = dragDropToImageForm.fp.file('dragitem[' + dragNo + ']').href;\n                    if (imgUrl === null) {\n                        continue;\n                    }\n                    // Althoug these are previews of drops, we also add the class name 'drag',\n                    dropZoneHolder.append('<img class=\"droppreview group' + group + ' drop' + dropNo +\n                            '\" src=\"' + imgUrl + '\" alt=\"' + label + '\" data-drop-no=\"' + dropNo + '\">');\n\n                } else if (label !== '') {\n                    dropZoneHolder.append('<div class=\"droppreview group' + group + ' drop' + dropNo +\n                        '\"  data-drop-no=\"' + dropNo + '\">' + label + '</div>');\n                }\n            }\n\n            dragDropToImageForm.waitForAllDropImagesToBeLoaded();\n        },\n\n        /**\n         * This polls until all the drop-zone images have loaded, and then calls updateDropZones().\n         */\n        waitForAllDropImagesToBeLoaded: function() {\n            var notYetLoadedImages = $('.dropzones img').not(function(i, imgNode) {\n                return dragDropToImageForm.imageIsLoaded(imgNode);\n            });\n\n            if (notYetLoadedImages.length > 0) {\n                setTimeout(function() {\n                    dragDropToImageForm.waitForAllDropImagesToBeLoaded();\n                }, 100);\n                return;\n            }\n\n            dragDropToImageForm.updateDropZones();\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        imageIsLoaded: function(imgElement) {\n            return imgElement.complete && imgElement.naturalHeight !== 0;\n        },\n\n        /**\n         * Set the size and position of all the drop zones.\n         */\n        updateDropZones: function() {\n            var bgimageurl = dragDropToImageForm.fp.file('bgimage').href;\n            if (bgimageurl === null) {\n                return; // There is not currently a valid preview to update.\n            }\n\n            var dropBackgroundPosition = $('fieldset#id_previewareaheader .dropbackground').offset(),\n                numDrops = dragDropToImageForm.form.getFormValue('nodropzone', []);\n\n            // Move each drop to the right position and update the text.\n            for (var dropNo = 0; dropNo < numDrops; dropNo++) {\n                var drop = $('.dropzones .drop' + dropNo);\n                if (drop.length === 0) {\n                    continue;\n                }\n                var dragNo = dragDropToImageForm.form.getFormValue('drops', [dropNo, 'choice']) - 1;\n\n                drop.offset({\n                    left: dropBackgroundPosition.left +\n                            parseInt(dragDropToImageForm.form.getFormValue('drops', [dropNo, 'xleft'])),\n                    top: dropBackgroundPosition.top +\n                            parseInt(dragDropToImageForm.form.getFormValue('drops', [dropNo, 'ytop']))\n                });\n\n                var label = dragDropToImageForm.form.getFormValue('draglabel', [dragNo]);\n                if (drop.is('img')) {\n                    drop.attr('alt', label);\n                } else {\n                    drop.html(label);\n                }\n            }\n\n            // Resize them to the same size.\n            $('.dropzones .droppreview').css('padding', '0');\n            var numGroups = $('.draggroup select').first().find('option').length;\n            for (var group = 1; group <= numGroups; group++) {\n                dragDropToImageForm.resizeAllDragsAndDropsInGroup(group);\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        resizeAllDragsAndDropsInGroup: function(group) {\n            var drops = $('.dropzones .droppreview.group' + group),\n                maxWidth = 0,\n                maxHeight = 0;\n\n            // Find the maximum size of any drag in this groups.\n            drops.each(function(i, drop) {\n                maxWidth = Math.max(maxWidth, Math.ceil(drop.offsetWidth));\n                maxHeight = Math.max(maxHeight, Math.ceil(drop.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            drops.each(function(i, drop) {\n                var left = Math.round((maxWidth - drop.offsetWidth) / 2),\n                    top = Math.floor((maxHeight - drop.offsetHeight) / 2);\n                // Set top and left padding so the item is centred.\n                $(drop).css({\n                    'padding-left': left + 'px',\n                    'padding-right': (maxWidth - drop.offsetWidth - left) + 'px',\n                    'padding-top': top + 'px',\n                    'padding-bottom': (maxHeight - drop.offsetHeight - top) + 'px'\n                });\n            });\n        },\n\n        /**\n         * Events linked to form actions.\n         */\n        setupEventHandlers: function() {\n            // Changes to settings in the draggable items section.\n            $('fieldset#id_draggableitemheader')\n                .on('change input', 'input, select', function(e) {\n                    var input = $(e.target).closest('select, input');\n                    if (input.hasClass('dragitemtype')) {\n                        dragDropToImageForm.updateVisibilityOfFilePickers();\n                    }\n\n                    dragDropToImageForm.setOptionsForDragItemSelectors();\n\n                    if (input.is('.dragitemtype, .draggroup')) {\n                        dragDropToImageForm.createDropZones();\n                    } else if (input.is('.draglabel')) {\n                        dragDropToImageForm.updateDropZones();\n                    }\n                });\n\n            // Changes to Drop zones section: left, top and drag item.\n            $('fieldset#id_dropzoneheader').on('change input', 'input, select', function(e) {\n                var input = $(e.target).closest('select, input');\n                if (input.is('select')) {\n                    dragDropToImageForm.createDropZones();\n                } else {\n                    dragDropToImageForm.updateDropZones();\n                }\n            });\n\n            // Moving drop zones in the preview.\n            $('fieldset#id_previewareaheader').on('mousedown touchstart', '.droppreview', function(e) {\n                dragDropToImageForm.dragStart(e);\n            });\n\n            $(window).on('resize', function() {\n                dragDropToImageForm.updateDropZones();\n            });\n        },\n\n        /**\n         * Update all the drag item filepickers, so they are only shown for\n         */\n        updateVisibilityOfFilePickers: function() {\n            var numDrags = dragDropToImageForm.form.getFormValue('noitems', []);\n            for (var dragNo = 0; dragNo < numDrags; dragNo++) {\n                var picker = $('input#id_dragitem_' + dragNo).closest('.fitem_ffilepicker');\n                if ('image' === dragDropToImageForm.form.getFormValue('drags', [dragNo, 'dragitemtype'])) {\n                    picker.show();\n                } else {\n                    picker.hide();\n                }\n            }\n        },\n\n\n        setOptionsForDragItemSelectors: function() {\n            var dragItemOptions = {'0': ''},\n                numDrags = dragDropToImageForm.form.getFormValue('noitems', []),\n                numDrops = dragDropToImageForm.form.getFormValue('nodropzone', []);\n\n            // Work out the list of options.\n            for (var dragNo = 0; dragNo < numDrags; dragNo++) {\n                var label = dragDropToImageForm.form.getFormValue('draglabel', [dragNo]);\n                var file = dragDropToImageForm.fp.file(dragDropToImageForm.form.toNameWithIndex('dragitem', [dragNo]));\n                if ('image' === dragDropToImageForm.form.getFormValue('drags', [dragNo, 'dragitemtype']) && file.name !== null) {\n                    dragItemOptions[dragNo + 1] = (dragNo + 1) + '. ' + label + ' (' + file.name + ')';\n                } else if (label !== '') {\n                    dragItemOptions[dragNo + 1] = (dragNo + 1) + '. ' + label;\n                }\n            }\n\n            // Initialise each select.\n            for (var dropNo = 0; dropNo < numDrops; dropNo++) {\n                var selector = $('#id_drops_' + dropNo + '_choice');\n\n                var selectedvalue = selector.val();\n                selector.find('option').remove();\n                for (var value in dragItemOptions) {\n                    if (!dragItemOptions.hasOwnProperty(value)) {\n                        continue;\n                    }\n                    selector.append('<option value=\"' + value + '\">' + dragItemOptions[value] + '</option>');\n                    var optionnode = selector.find('option[value=\"' + value + '\"]');\n                    if (parseInt(value) === parseInt(selectedvalue)) {\n                        optionnode.attr('selected', true);\n                    } else if (dragDropToImageForm.isItemUsed(parseInt(value))) {\n                        optionnode.attr('disabled', true);\n                    }\n                }\n            }\n        },\n\n        /**\n         * Checks if the specified drag option is already used somewhere.\n         *\n         * @param {Number} value of the drag item to check\n         * @return {Boolean} true if item is allocated to dropzone\n         */\n        isItemUsed: function(value) {\n            if (value === 0) {\n                return false; // None option can always be selected.\n            }\n\n            if (dragDropToImageForm.form.getFormValue('drags', [value - 1, 'infinite'])) {\n                return false; // Infinite, so can't be used up.\n            }\n\n            return $('fieldset#id_dropzoneheader select').filter(function(i, selectNode) {\n                return parseInt($(selectNode).val()) === value;\n            }).length !== 0;\n        },\n\n        /**\n         * Handles when a dropzone in dragged in the preview.\n         * @param {Object} e Event object\n         */\n        dragStart: function(e) {\n            var drop = $(e.target).closest('.droppreview');\n\n            var info = dragDrop.prepare(e);\n            if (!info.start) {\n                return;\n            }\n\n            dragDrop.start(e, drop, function(x, y, drop) {\n                dragDropToImageForm.dragMove(drop);\n            }, function() {\n                dragDropToImageForm.dragEnd();\n            });\n        },\n\n        /**\n         * Handles update while a drop is being dragged.\n         *\n         * @param {jQuery} drop the drop preview being moved.\n         */\n        dragMove: function(drop) {\n            var backgroundImage = $('fieldset#id_previewareaheader .dropbackground'),\n                backgroundPosition = backgroundImage.offset(),\n                dropNo = drop.data('dropNo'),\n                dropPosition = drop.offset(),\n                left = Math.round(dropPosition.left - backgroundPosition.left),\n                top = Math.round(dropPosition.top - backgroundPosition.top);\n\n            // Constrain coordinates to be inside the background.\n            left = Math.round(Math.max(0, Math.min(left, backgroundImage.outerWidth() - drop.outerWidth())));\n            top = Math.round(Math.max(0, Math.min(top, backgroundImage.outerHeight() - drop.outerHeight())));\n\n            // Update the form.\n            dragDropToImageForm.form.setFormValue('drops', [dropNo, 'xleft'], left);\n            dragDropToImageForm.form.setFormValue('drops', [dropNo, 'ytop'], top);\n        },\n\n        /**\n         * Handles when the drag ends.\n         */\n        dragEnd: function() {\n            // Redraw, in case the position was constrained.\n            dragDropToImageForm.updateDropZones();\n        },\n\n        /**\n         * Low level operations on form.\n         */\n        form: {\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=\"ddimageortext\"]')[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][xleft]\".\n             *\n             * @param {String} name the base name, e.g. 'drops'.\n             * @param {String[]} indexes the indexes, e.g. ['0', 'xleft'].\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) {\n                    el = el[el.length - 1];\n                }\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][xleft]\".\n             *\n             * @param {String} name the base name, e.g. 'drops'.\n             * @param {String[]} indexes the indexes, e.g. ['0', 'xleft'].\n             * @param {String|Number} 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\n            if (draftItemIdsToName === undefined) {\n                draftItemIdsToName = {};\n                nameToParentNode = {};\n                var fp = $('form.mform[data-qtype=\"ddimageortext\"] input.filepickerhidden');\n                fp.each(function(index, filepicker) {\n                    draftItemIdsToName[filepicker.value] = filepicker.name;\n                    nameToParentNode[filepicker.name] = filepicker.parentNode;\n                });\n            }\n\n            return {\n                file: function(name) {\n                    var parentNode = $(nameToParentNode[name]);\n                    var fileAnchor = parentNode.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\n                name: function(draftitemid) {\n                    return draftItemIdsToName[draftitemid];\n                }\n            };\n        }\n    };\n\n    return {\n        init: dragDropToImageForm.init\n    };\n});\n"],"names":["define","$","dragDrop","dragDropToImageForm","maxBgImageSize","maxDragImageSize","fp","init","filePickers","updateVisibilityOfFilePickers","setOptionsForDragItemSelectors","setupEventHandlers","waitForFilePickerToInitialise","setupPreviewArea","append","file","href","M","util","js_pending","on","loadPreviewImage","length","setTimeout","one","afterPreviewImageLoaded","attr","createDropZones","js_complete","dropZoneHolder","empty","numDrops","form","getFormValue","dropNo","dragNo","group","label","imgUrl","waitForAllDropImagesToBeLoaded","not","i","imgNode","imageIsLoaded","updateDropZones","imgElement","complete","naturalHeight","dropBackgroundPosition","offset","drop","left","parseInt","top","is","html","css","numGroups","first","find","resizeAllDragsAndDropsInGroup","drops","maxWidth","maxHeight","each","Math","max","ceil","offsetWidth","offsetHeight","round","floor","e","input","target","closest","hasClass","dragStart","window","numDrags","picker","show","hide","dragItemOptions","toNameWithIndex","name","selector","selectedvalue","val","value","remove","hasOwnProperty","optionnode","isItemUsed","filter","selectNode","prepare","start","x","y","dragMove","dragEnd","backgroundImage","backgroundPosition","data","dropPosition","min","outerWidth","outerHeight","setFormValue","indexes","indexString","getEl","elements","this","el","type","checked","draftItemIdsToName","nameToParentNode","undefined","index","filepicker","parentNode","fileAnchor","get","innerHTML","draftitemid"],"mappings":"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"}