From ebf91776d7a9eb2d8a08ad879fb5030a207b4797 Mon Sep 17 00:00:00 2001 From: Tim Hunt Date: Mon, 3 Sep 2018 13:16:16 +0100 Subject: [PATCH] MDL-63297 qtype_ddimageortext: re-implement JavaScript in AMD this kills of a bunch of old YUI code. Should also make this question type work a bit mroe robustly. --- .../type/ddimageortext/amd/build/form.min.js | 1 + .../ddimageortext/amd/build/question.min.js | 1 + question/type/ddimageortext/amd/src/form.js | 541 +++++++++++++ .../type/ddimageortext/amd/src/question.js | 760 ++++++++++++++++++ .../ddimageortext/edit_ddimageortext_form.php | 27 +- question/type/ddimageortext/rendererbase.php | 23 +- question/type/ddimageortext/styles.css | 112 +-- .../tests/behat/behat_qtype_ddimageortext.php | 6 +- .../ddimageortext/tests/behat/preview.feature | 4 +- .../ddimageortext/tests/walkthrough_test.php | 3 +- .../moodle-qtype_ddimageortext-dd-debug.js | 546 ------------- .../moodle-qtype_ddimageortext-dd-min.js | 2 - .../moodle-qtype_ddimageortext-dd.js | 546 ------------- .../moodle-qtype_ddimageortext-form-debug.js | 369 --------- .../moodle-qtype_ddimageortext-form-min.js | 2 - .../moodle-qtype_ddimageortext-form.js | 369 --------- .../yui/src/ddimageortext/build.json | 10 - .../yui/src/ddimageortext/js/ddimageortext.js | 541 ------------- .../src/ddimageortext/meta/ddimageortext.json | 10 - .../ddimageortext/yui/src/form/build.json | 10 - .../ddimageortext/yui/src/form/js/form.js | 364 --------- .../ddimageortext/yui/src/form/meta/form.json | 8 - 22 files changed, 1387 insertions(+), 2868 deletions(-) create mode 100644 question/type/ddimageortext/amd/build/form.min.js create mode 100644 question/type/ddimageortext/amd/build/question.min.js create mode 100644 question/type/ddimageortext/amd/src/form.js create mode 100644 question/type/ddimageortext/amd/src/question.js delete mode 100644 question/type/ddimageortext/yui/build/moodle-qtype_ddimageortext-dd/moodle-qtype_ddimageortext-dd-debug.js delete mode 100644 question/type/ddimageortext/yui/build/moodle-qtype_ddimageortext-dd/moodle-qtype_ddimageortext-dd-min.js delete mode 100644 question/type/ddimageortext/yui/build/moodle-qtype_ddimageortext-dd/moodle-qtype_ddimageortext-dd.js delete mode 100644 question/type/ddimageortext/yui/build/moodle-qtype_ddimageortext-form/moodle-qtype_ddimageortext-form-debug.js delete mode 100644 question/type/ddimageortext/yui/build/moodle-qtype_ddimageortext-form/moodle-qtype_ddimageortext-form-min.js delete mode 100644 question/type/ddimageortext/yui/build/moodle-qtype_ddimageortext-form/moodle-qtype_ddimageortext-form.js delete mode 100644 question/type/ddimageortext/yui/src/ddimageortext/build.json delete mode 100644 question/type/ddimageortext/yui/src/ddimageortext/js/ddimageortext.js delete mode 100644 question/type/ddimageortext/yui/src/ddimageortext/meta/ddimageortext.json delete mode 100644 question/type/ddimageortext/yui/src/form/build.json delete mode 100644 question/type/ddimageortext/yui/src/form/js/form.js delete mode 100644 question/type/ddimageortext/yui/src/form/meta/form.json diff --git a/question/type/ddimageortext/amd/build/form.min.js b/question/type/ddimageortext/amd/build/form.min.js new file mode 100644 index 0000000000000..e981a66195707 --- /dev/null +++ b/question/type/ddimageortext/amd/build/form.min.js @@ -0,0 +1 @@ +define(["jquery","core/dragdrop"],function(a,b){"use strict";var c={maxBgImageSize:null,maxDragImageSize:null,fp:null,init:function(b,d){c.maxBgImageSize=b,c.maxDragImageSize=d,c.fp=c.filePickers(),a("#id_previewareaheader").append('
'),c.updateVisibilityOfFilePickers(),c.setOptionsForDragItemSelectors(),c.setupEventHandlers(),c.waitForFilePickerToInitialise()},waitForFilePickerToInitialise:function(){return null===c.fp.file("bgimage").href?void setTimeout(c.waitForFilePickerToInitialise,1e3):(M.util.js_pending("dragDropToImageForm"),a("form.mform").on("change",".filepickerhidden",function(){M.util.js_pending("dragDropToImageForm"),c.loadPreviewImage()}),void c.loadPreviewImage())},loadPreviewImage:function(){a("fieldset#id_previewareaheader .dropbackground").one("load",c.afterPreviewImageLoaded).attr("src",c.fp.file("bgimage").href)},afterPreviewImageLoaded:function(){var b=a("fieldset#id_previewareaheader .dropbackground");c.constrainImageSize(b,c.maxBgImageSize),c.createDropZones(),M.util.js_complete("dragDropToImageForm")},constrainImageSize:function(a,b){var c=Math.max(a.width()/b.width,a.height()/b.height);c>1&&a.css("width",Math.floor(a.width()/c)),a.addClass("constrained")},createDropZones:function(){var b=a(".dropzones");b.empty();var d=c.fp.file("bgimage").href;if(null!==d){for(var e=c.form.getFormValue("nodropzone",[]),f=0;f')}else""!==i&&b.append('
'+i+"
")}}c.waitForAllDropImagesToBeLoaded()}},waitForAllDropImagesToBeLoaded:function(){var b=a(".dropzones img").not(function(a,b){return c.imageIsLoaded(b)});return b.length>0?void setTimeout(function(){c.waitForAllDropImagesToBeLoaded()},100):void c.updateDropZones()},imageIsLoaded:function(a){return a.complete&&0!==a.naturalHeight},updateDropZones:function(){var b=c.fp.file("bgimage").href;if(null!==b){for(var d=a("fieldset#id_previewareaheader .dropbackground").offset(),e=c.form.getFormValue("nodropzone",[]),f=0;f'+b[l]+"");var m=j.find('option[value="'+l+'"]');parseInt(l)===parseInt(k)?m.attr("selected",!0):c.isItemUsed(parseInt(l))&&m.attr("disabled",!0)}}},isItemUsed:function(b){return 0!==b&&(!c.form.getFormValue("drags",[b-1,"infinite"])&&0!==a("fieldset#id_dropzoneheader select").filter(function(c,d){return parseInt(a(d).val())===b}).length)},dragStart:function(d){var e=a(d.target).closest(".droppreview"),f=b.prepare(d);f.start&&b.start(d,e,function(a,b,d){c.dragMove(d)},function(){c.dragEnd()})},dragMove:function(b){var d=a("fieldset#id_previewareaheader .dropbackground"),e=d.offset(),f=b.data("dropNo"),g=b.offset(),h=Math.round(g.left-e.left),i=Math.round(g.top-e.top);h=Math.max(0,Math.min(h,d.width()-b.width()-10)),i=Math.max(0,Math.min(i,d.height()-b.height()-10)),c.form.setFormValue("drops",[f,"xleft"],h),c.form.setFormValue("drops",[f,"ytop"],i)},dragEnd:function(){c.updateDropZones()},form:{toNameWithIndex:function(a,b){for(var c=a,d=0;d0)return void(this.imageLoadingTimeoutId=setTimeout(function(){a.waitForAllImagesToBeLoaded()},100));this.allImagesLoaded=!0,a.setupQuestion()}},d.prototype.getNotYetLoadedImages=function(){var a=this;return this.getRoot().find(".ddarea img").not(function(b,c){return a.imageIsLoaded(c)})},d.prototype.imageIsLoaded=function(a){return a.complete&&0!==a.naturalHeight},d.prototype.setupQuestion=function(){this.resizeAllDragsAndDrops(),this.cloneDrags(),this.positionDragsAndDrops(),M.util.js_complete("qtype_ddimageortext-init-"+this.containerId)},d.prototype.resizeAllDragsAndDrops=function(){var a=this;this.getRoot().find(".draghomes > div").each(function(b){a.resizeAllDragsAndDropsInGroup(b+1)})},d.prototype.resizeAllDragsAndDropsInGroup=function(b){var c=this.getRoot(),d=c.find(".dragitemgroup"+b+" .draghome"),e=0,f=0;d.each(function(a,b){e=Math.max(e,Math.ceil(b.offsetWidth)),f=Math.max(f,Math.ceil(b.offsetHeight))}),e+=10,f+=10,d.each(function(b,c){var d=Math.round((e-c.offsetWidth)/2),g=Math.floor((f-c.offsetHeight)/2);a(c).css({"padding-left":d+"px","padding-right":e-c.offsetWidth-d+"px","padding-top":g+"px","padding-bottom":f-c.offsetHeight-g+"px"})});for(var g in this.places)if(this.places.hasOwnProperty(g)){var h=this.places[g],i=h.text;parseInt(h.group)===b&&(""===i&&(i=M.util.get_string("blank","qtype_ddimageortext")),c.find(".dropzones").append('
'+i+" 
"),c.find(".dropzone.place"+g).width(e-2).height(f-2))}},d.prototype.cloneDrags=function(){var b=this;this.getRoot().find(".ddarea .draghome").each(function(c,d){b.cloneDragsForOneChoice(a(d))})},d.prototype.cloneDragsForOneChoice=function(a){if(a.hasClass("infinite"))for(var b=this.noOfDropsInGroup(this.getGroup(a)),c=0;c1;)c--,d=this.getUnplacedChoice(a,c);return d},d.prototype.animateTo=function(a,b){var c=a.offset(),d=b.offset();a.addClass("beingdragged"),a.animate({left:parseInt(a.css("left"))+d.left-c.left,top:parseInt(a.css("top"))+d.top-c.top},{duration:"fast",done:function(){a.removeClass("beingdragged"),a.offset(d)}})},d.prototype.isPointInDrop=function(a,b,c){var d=c.offset();return a>=d.left&&a=d.top&&b. + +/* + * JavaScript to allow dragging options to slots (using mouse down or touch) or tab through slots using keyboard. + * + * @module qtype_ddimageortext/form + * @package qtype_ddimageortext + * @copyright 2018 The Open University + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +define(['jquery', 'core/dragdrop'], function($, dragDrop) { + + "use strict"; + + /** + * Singleton object to handle progressive enhancement of the + * drag-drop onto image question editing form. + * @type {Object} + */ + var dragDropToImageForm = { + /** + * @var {Object} with properties width and height. + */ + maxBgImageSize: null, + + /** + * @var {Object} with properties width and height. + */ + maxDragImageSize: null, + + /** + * @var {object} for interacting with the file pickers. + */ + fp: null, // Object containing functions associated with the file picker. + + /** + * Initialise the form javascript features. + * + * @param {Object} maxBgImageSize object with two properties: width and height. + * @param {Object} maxDragImageSize object with two properties: width and height. + */ + init: function(maxBgImageSize, maxDragImageSize) { + dragDropToImageForm.maxBgImageSize = maxBgImageSize; + dragDropToImageForm.maxDragImageSize = maxDragImageSize; + dragDropToImageForm.fp = dragDropToImageForm.filePickers(); + + $('#id_previewareaheader').append( + '
' + + '
' + + ' ' + + '
' + + '
' + + '
' + + '
'); + + dragDropToImageForm.updateVisibilityOfFilePickers(); + dragDropToImageForm.setOptionsForDragItemSelectors(); + dragDropToImageForm.setupEventHandlers(); + dragDropToImageForm.waitForFilePickerToInitialise(); + }, + + /** + * Waits for the file-pickers to be sufficiently ready before initialising the preview. + */ + waitForFilePickerToInitialise: function() { + if (dragDropToImageForm.fp.file('bgimage').href === null) { + // It would be better to use an onload or onchange event rather than this timeout. + // Unfortunately attempts to do this early are overwritten by filepicker during its loading. + setTimeout(dragDropToImageForm.waitForFilePickerToInitialise, 1000); + return; + } + M.util.js_pending('dragDropToImageForm'); + + // From now on, when a new file gets loaded into the filepicker, update the preview. + // This is not in the setupEventHandlers section as it needs to be delayed until + // after filepicker's javascript has finished. + $('form.mform').on('change', '.filepickerhidden', function() { + M.util.js_pending('dragDropToImageForm'); + dragDropToImageForm.loadPreviewImage(); + }); + + dragDropToImageForm.loadPreviewImage(); + }, + + /** + * Loads the preview background image. + */ + loadPreviewImage: function() { + $('fieldset#id_previewareaheader .dropbackground') + .one('load', dragDropToImageForm.afterPreviewImageLoaded) + .attr('src', dragDropToImageForm.fp.file('bgimage').href); + }, + + /** + * After the background image is loaded, continue setting up the preview. + */ + afterPreviewImageLoaded: function() { + var bgImg = $('fieldset#id_previewareaheader .dropbackground'); + dragDropToImageForm.constrainImageSize(bgImg, dragDropToImageForm.maxBgImageSize); + dragDropToImageForm.createDropZones(); + M.util.js_complete('dragDropToImageForm'); + }, + + /** + * Limits an image display size to the given maximums. + * + * @param {jQuery} img the image. + * @param {Object} maxSize with width and height properties. + */ + constrainImageSize: function(img, maxSize) { + var reduceby = Math.max(img.width() / maxSize.width, + img.height() / maxSize.height); + if (reduceby > 1) { + img.css('width', Math.floor(img.width() / reduceby)); + } + img.addClass('constrained'); + }, + + /** + * Create, or recreate all the drop zones. + */ + createDropZones: function() { + var dropZoneHolder = $('.dropzones'); + dropZoneHolder.empty(); + + var bgimageurl = dragDropToImageForm.fp.file('bgimage').href; + if (bgimageurl === null) { + return; // There is not currently a valid preview to update. + } + + var numDrops = dragDropToImageForm.form.getFormValue('nodropzone', []); + for (var dropNo = 0; dropNo < numDrops; dropNo++) { + var dragNo = dragDropToImageForm.form.getFormValue('drops', [dropNo, 'choice']); + if (dragNo === '0') { + continue; + } + dragNo = dragNo - 1; + var group = dragDropToImageForm.form.getFormValue('drags', [dragNo, 'draggroup']), + label = dragDropToImageForm.form.getFormValue('draglabel', [dragNo]); + if ('image' === dragDropToImageForm.form.getFormValue('drags', [dragNo, 'dragitemtype'])) { + var imgUrl = dragDropToImageForm.fp.file('dragitem[' + dragNo + ']').href; + if (imgUrl === null) { + continue; + } + // Althoug these are previews of drops, we also add the class name 'drag', + dropZoneHolder.append('' + label + ''); + + } else if (label !== '') { + dropZoneHolder.append('
' + label + '
'); + } + } + + dragDropToImageForm.waitForAllDropImagesToBeLoaded(); + }, + + /** + * This polls until all the drop-zone images have loaded, and then calls updateDropZones(). + */ + waitForAllDropImagesToBeLoaded: function() { + var notYetLoadedImages = $('.dropzones img').not(function(i, imgNode) { + return dragDropToImageForm.imageIsLoaded(imgNode); + }); + + if (notYetLoadedImages.length > 0) { + setTimeout(function() { + dragDropToImageForm.waitForAllDropImagesToBeLoaded(); + }, 100); + return; + } + + dragDropToImageForm.updateDropZones(); + }, + + /** + * Check if an image has loaded without errors. + * + * @param {HTMLImageElement} imgElement an image. + * @returns {boolean} true if this image has loaded without errors. + */ + imageIsLoaded: function(imgElement) { + return imgElement.complete && imgElement.naturalHeight !== 0; + }, + + /** + * Set the size and position of all the drop zones. + */ + updateDropZones: function() { + var bgimageurl = dragDropToImageForm.fp.file('bgimage').href; + if (bgimageurl === null) { + return; // There is not currently a valid preview to update. + } + + var dropBackgroundPosition = $('fieldset#id_previewareaheader .dropbackground').offset(), + numDrops = dragDropToImageForm.form.getFormValue('nodropzone', []); + + // Move each drop to the right position and update the text. + for (var dropNo = 0; dropNo < numDrops; dropNo++) { + var drop = $('.dropzones .drop' + dropNo); + if (drop.length === 0) { + continue; + } + var dragNo = dragDropToImageForm.form.getFormValue('drops', [dropNo, 'choice']) - 1; + + drop.offset({ + left: dropBackgroundPosition.left + + parseInt(dragDropToImageForm.form.getFormValue('drops', [dropNo, 'xleft'])), + top: dropBackgroundPosition.top + + parseInt(dragDropToImageForm.form.getFormValue('drops', [dropNo, 'ytop'])) + }); + + var label = dragDropToImageForm.form.getFormValue('draglabel', [dragNo]); + if (drop.is('img')) { + drop.attr('alt', label); + } else { + drop.html(label); + } + } + + // Resize them to the same size. + $('.dropzones .droppreview').css('padding', '0'); + var numGroups = $('select.draggroup').first().find('option').length; + for (var group = 1; group <= numGroups; group++) { + dragDropToImageForm.resizeAllDragsAndDropsInGroup(group); + } + }, + + /** + * In a given group, set all the drags and drops to be the same size. + * + * @param {int} group the group number. + */ + resizeAllDragsAndDropsInGroup: function(group) { + var drops = $('.dropzones .droppreview.group' + group), + maxWidth = 0, + maxHeight = 0; + + // Find the maximum size of any drag in this groups. + drops.each(function(i, drop) { + maxWidth = Math.max(maxWidth, Math.ceil(drop.offsetWidth)); + maxHeight = Math.max(maxHeight, Math.ceil(drop.offsetHeight)); + }); + + // The size we will want to set is a bit bigger than this. + maxWidth += 10; + maxHeight += 10; + + // Set each drag home to that size. + drops.each(function(i, drop) { + var left = Math.round((maxWidth - drop.offsetWidth) / 2), + top = Math.floor((maxHeight - drop.offsetHeight) / 2); + // Set top and left padding so the item is centred. + $(drop).css({ + 'padding-left': left + 'px', + 'padding-right': (maxWidth - drop.offsetWidth - left) + 'px', + 'padding-top': top + 'px', + 'padding-bottom': (maxHeight - drop.offsetHeight - top) + 'px' + }); + }); + }, + + /** + * Events linked to form actions. + */ + setupEventHandlers: function() { + // Changes to settings in the draggable items section. + $('fieldset#id_draggableitemheader') + .on('change input', 'input, select', function(e) { + var input = $(e.target).closest('select, input'); + if (input.hasClass('dragitemtype')) { + dragDropToImageForm.updateVisibilityOfFilePickers(); + } + + dragDropToImageForm.setOptionsForDragItemSelectors(); + + if (input.is('.dragitemtype, .draggroup')) { + dragDropToImageForm.createDropZones(); + } else if (input.is('.draglabel')) { + dragDropToImageForm.updateDropZones(); + } + }); + + // Changes to Drop zones section: left, top and drag item. + $('fieldset#id_dropzoneheader').on('change input', 'input, select', function(e) { + var input = $(e.target).closest('select, input'); + if (input.is('select')) { + dragDropToImageForm.createDropZones(); + } else { + dragDropToImageForm.updateDropZones(); + } + }); + + // Moving drop zones in the preview. + $('fieldset#id_previewareaheader').on('mousedown touchstart', '.droppreview', function(e) { + dragDropToImageForm.dragStart(e); + }); + + $(window).on('resize', function() { + dragDropToImageForm.updateDropZones(); + }); + }, + + /** + * Update all the drag item filepickers, so they are only shown for + */ + updateVisibilityOfFilePickers: function() { + var numDrags = dragDropToImageForm.form.getFormValue('noitems', []); + for (var dragNo = 0; dragNo < numDrags; dragNo++) { + var picker = $('input#id_dragitem_' + dragNo).closest('.fitem_ffilepicker'); + if ('image' === dragDropToImageForm.form.getFormValue('drags', [dragNo, 'dragitemtype'])) { + picker.show(); + } else { + picker.hide(); + } + } + }, + + + setOptionsForDragItemSelectors: function() { + var dragItemOptions = {'0': ''}, + numDrags = dragDropToImageForm.form.getFormValue('noitems', []), + numDrops = dragDropToImageForm.form.getFormValue('nodropzone', []); + + // Work out the list of options. + for (var dragNo = 0; dragNo < numDrags; dragNo++) { + var label = dragDropToImageForm.form.getFormValue('draglabel', [dragNo]); + var file = dragDropToImageForm.fp.file(dragDropToImageForm.form.toNameWithIndex('dragitem', [dragNo])); + if ('image' === dragDropToImageForm.form.getFormValue('drags', [dragNo, 'dragitemtype']) && file.name !== null) { + dragItemOptions[dragNo + 1] = (dragNo + 1) + '. ' + label + ' (' + file.name + ')'; + } else if (label !== '') { + dragItemOptions[dragNo + 1] = (dragNo + 1) + '. ' + label; + } + } + + // Initialise each select. + for (var dropNo = 0; dropNo < numDrops; dropNo++) { + var selector = $('#id_drops_' + dropNo + '_choice'); + + var selectedvalue = selector.val(); + selector.find('option').remove(); + for (var value in dragItemOptions) { + if (!dragItemOptions.hasOwnProperty(value)) { + continue; + } + selector.append(''); + var optionnode = selector.find('option[value="' + value + '"]'); + if (parseInt(value) === parseInt(selectedvalue)) { + optionnode.attr('selected', true); + } else if (dragDropToImageForm.isItemUsed(parseInt(value))) { + optionnode.attr('disabled', true); + } + } + } + }, + + /** + * Checks if the specified drag option is already used somewhere. + * + * @param {Number} value of the drag item to check + * @return {Boolean} true if item is allocated to dropzone + */ + isItemUsed: function(value) { + if (value === 0) { + return false; // None option can always be selected. + } + + if (dragDropToImageForm.form.getFormValue('drags', [value - 1, 'infinite'])) { + return false; // Infinite, so can't be used up. + } + + return $('fieldset#id_dropzoneheader select').filter(function(i, selectNode) { + return parseInt($(selectNode).val()) === value; + }).length !== 0; + }, + + /** + * Handles when a dropzone in dragged in the preview. + * @param {Object} e Event object + */ + dragStart: function(e) { + var drop = $(e.target).closest('.droppreview'); + + var info = dragDrop.prepare(e); + if (!info.start) { + return; + } + + dragDrop.start(e, drop, function(x, y, drop) { + dragDropToImageForm.dragMove(drop); + }, function() { + dragDropToImageForm.dragEnd(); + }); + }, + + /** + * Handles update while a drop is being dragged. + * + * @param {jQuery} drop the drop preview being moved. + */ + dragMove: function(drop) { + var backgroundImage = $('fieldset#id_previewareaheader .dropbackground'), + backgroundPosition = backgroundImage.offset(), + dropNo = drop.data('dropNo'), + dropPosition = drop.offset(), + left = Math.round(dropPosition.left - backgroundPosition.left), + top = Math.round(dropPosition.top - backgroundPosition.top); + + // Constrain coordinates to be inside the background. + // The -10 here matches the +10 in resizeAllDragsAndDropsInGroup(). + left = Math.max(0, Math.min(left, backgroundImage.width() - drop.width() - 10)); + top = Math.max(0, Math.min(top, backgroundImage.height() - drop.height() - 10)); + + // Update the form. + dragDropToImageForm.form.setFormValue('drops', [dropNo, 'xleft'], left); + dragDropToImageForm.form.setFormValue('drops', [dropNo, 'ytop'], top); + }, + + /** + * Handles when the drag ends. + */ + dragEnd: function() { + // Redraw, in case the position was constrained. + dragDropToImageForm.updateDropZones(); + }, + + /** + * Low level operations on form. + */ + form: { + toNameWithIndex: function(name, indexes) { + var indexString = name; + for (var i = 0; i < indexes.length; i++) { + indexString = indexString + '[' + indexes[i] + ']'; + } + return indexString; + }, + + getEl: function(name, indexes) { + var form = document.getElementById('mform1'); + return form.elements[this.toNameWithIndex(name, indexes)]; + }, + + /** + * Helper to get the value of a form elements with name like "drops[0][xleft]". + * + * @param {String} name the base name, e.g. 'drops'. + * @param {String[]} indexes the indexes, e.g. ['0', 'xleft']. + * @return {String} the value of that field. + */ + getFormValue: function(name, indexes) { + var el = this.getEl(name, indexes); + if (!el.type) { + el = el[el.length - 1]; + } + if (el.type === 'checkbox') { + return el.checked; + } else { + return el.value; + } + }, + + /** + * Helper to get the value of a form elements with name like "drops[0][xleft]". + * + * @param {String} name the base name, e.g. 'drops'. + * @param {String[]} indexes the indexes, e.g. ['0', 'xleft']. + * @param {String|Number} value the value to set. + */ + setFormValue: function(name, indexes, value) { + var el = this.getEl(name, indexes); + if (el.type === 'checkbox') { + el.checked = value; + } else { + el.value = value; + } + } + }, + + /** + * Utility to get the file name and url from the filepicker. + * @returns {Object} object containing functions {file, name} + */ + filePickers: function() { + var draftItemIdsToName; + var nameToParentNode; + + if (draftItemIdsToName === undefined) { + draftItemIdsToName = {}; + nameToParentNode = {}; + var fp = $('form.mform input.filepickerhidden'); + fp.each(function(index, filepicker) { + draftItemIdsToName[filepicker.value] = filepicker.name; + nameToParentNode[filepicker.name] = filepicker.parentNode; + }); + } + + return { + file: function(name) { + var parentNode = $(nameToParentNode[name]); + var fileAnchor = parentNode.find('div.filepicker-filelist a'); + if (fileAnchor.length) { + return {href: fileAnchor.get(0).href, name: fileAnchor.get(0).innerHTML}; + } else { + return {href: null, name: null}; + } + }, + + name: function(draftitemid) { + return draftItemIdsToName[draftitemid]; + } + }; + } + }; + + /** + * @alias module:qtype_ddimageortext/form + */ + return { + /** + * Initialise the form JavaScript features. + * + * @param {Object} maxBgImageSize object with two properties: width and height. + * @param {Object} maxDragImageSize object with two properties: width and height. + */ + init: dragDropToImageForm.init + }; +}); diff --git a/question/type/ddimageortext/amd/src/question.js b/question/type/ddimageortext/amd/src/question.js new file mode 100644 index 0000000000000..0dd8a4596d916 --- /dev/null +++ b/question/type/ddimageortext/amd/src/question.js @@ -0,0 +1,760 @@ +// This file is part of Moodle - http://moodle.org/ +// +// Moodle is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Moodle is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Moodle. If not, see . + +/* + * JavaScript to allow dragging options to slots (using mouse down or touch) or tab through slots using keyboard. + * + * @module qtype_ddimageortext/question + * @package qtype_ddimageortext + * @copyright 2018 The Open University + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +define(['jquery', 'core/dragdrop', 'core/key_codes'], function($, dragDrop, keys) { + + "use strict"; + + /** + * Initialise one drag-drop onto image question. + * + * @param {String} containerId id of the outer div for this question. + * @param {boolean} readOnly whether the question is being displayed read-only. + * @param {Array} places Information about the drop places. + * @constructor + */ + function DragDropOntoImageQuestion(containerId, readOnly, places) { + this.containerId = containerId; + M.util.js_pending('qtype_ddimageortext-init-' + this.containerId); + this.places = places; + this.allImagesLoaded = false; + this.imageLoadingTimeoutId = null; + if (readOnly) { + this.getRoot().addClass('qtype_ddimageortext-readonly'); + } + + var thisQ = this; + this.getNotYetLoadedImages().one('load', function() { + thisQ.waitForAllImagesToBeLoaded(); + }); + this.waitForAllImagesToBeLoaded(); + } + + /** + * Waits until all images are loaded before calling setupQuestion(). + * + * This function is called from the onLoad of each image, and also polls with + * a time-out, because image on-loads are allegedly unreliable. + */ + DragDropOntoImageQuestion.prototype.waitForAllImagesToBeLoaded = function() { + var thisQ = this; + + // This method may get called multiple times (via image on-loads or timeouts. + // If we are already done, don't do it again. + if (this.allImagesLoaded) { + return; + } + + // Clear any current timeout, if set. + if (this.imageLoadingTimeoutId !== null) { + clearTimeout(this.imageLoadingTimeoutId); + } + + // If we have not yet loaded all images, set a timeout to + // call ourselves again, since apparently images on-load + // events are flakey. + if (this.getNotYetLoadedImages().length > 0) { + this.imageLoadingTimeoutId = setTimeout(function() { + thisQ.waitForAllImagesToBeLoaded(); + }, 100); + return; + } + + // We now have all images. Carry on, but only after giving the layout a chance to settle down. + this.allImagesLoaded = true; + thisQ.setupQuestion(); + }; + + /** + * Get any of the images in the drag-drop area that are not yet fully loaded. + * + * @returns {jQuery} those images. + */ + DragDropOntoImageQuestion.prototype.getNotYetLoadedImages = function() { + var thisQ = this; + return this.getRoot().find('.ddarea img').not(function(i, imgNode) { + return thisQ.imageIsLoaded(imgNode); + }); + }; + + /** + * Check if an image has loaded without errors. + * + * @param {HTMLImageElement} imgElement an image. + * @returns {boolean} true if this image has loaded without errors. + */ + DragDropOntoImageQuestion.prototype.imageIsLoaded = function(imgElement) { + return imgElement.complete && imgElement.naturalHeight !== 0; + }; + + /** + * Set up the question, once all images have been loaded. + */ + DragDropOntoImageQuestion.prototype.setupQuestion = function() { + this.resizeAllDragsAndDrops(); + this.cloneDrags(); + this.positionDragsAndDrops(); + M.util.js_complete('qtype_ddimageortext-init-' + this.containerId); + + }; + + /** + * In each group, resize all the items to be the same size. + */ + DragDropOntoImageQuestion.prototype.resizeAllDragsAndDrops = function() { + var thisQ = this; + this.getRoot().find('.draghomes > div').each(function(i) { + thisQ.resizeAllDragsAndDropsInGroup(i + 1); + }); + }; + + /** + * In a given group, set all the drags and drops to be the same size. + * + * @param {int} group the group number. + */ + DragDropOntoImageQuestion.prototype.resizeAllDragsAndDropsInGroup = function(group) { + var root = this.getRoot(), + dragHomes = root.find('.dragitemgroup' + group + ' .draghome'), + maxWidth = 0, + maxHeight = 0; + + // Find the maximum size of any drag in this groups. + dragHomes.each(function(i, drag) { + maxWidth = Math.max(maxWidth, Math.ceil(drag.offsetWidth)); + maxHeight = Math.max(maxHeight, Math.ceil(drag.offsetHeight)); + }); + + // The size we will want to set is a bit bigger than this. + maxWidth += 10; + maxHeight += 10; + + // Set each drag home to that size. + dragHomes.each(function(i, drag) { + var left = Math.round((maxWidth - drag.offsetWidth) / 2), + top = Math.floor((maxHeight - drag.offsetHeight) / 2); + // Set top and left padding so the item is centred. + $(drag).css({ + 'padding-left': left + 'px', + 'padding-right': (maxWidth - drag.offsetWidth - left) + 'px', + 'padding-top': top + 'px', + 'padding-bottom': (maxHeight - drag.offsetHeight - top) + 'px' + }); + }); + + // Create the drops and make them the right size. + for (var i in this.places) { + if (!this.places.hasOwnProperty((i))) { + continue; + } + var place = this.places[i], + label = place.text; + if (parseInt(place.group) !== group) { + continue; + } + if (label === '') { + label = M.util.get_string('blank', 'qtype_ddimageortext'); + } + root.find('.dropzones').append('
' + + '' + label + ' 
'); + root.find('.dropzone.place' + i).width(maxWidth - 2).height(maxHeight - 2); + } + }; + + /** + * Invisible 'drag homes' are output by the renderer. These have the same properties + * as the drag items but are invisible. We clone these invisible elements to make the + * actual drag items. + */ + DragDropOntoImageQuestion.prototype.cloneDrags = function() { + var thisQ = this; + this.getRoot().find('.ddarea .draghome').each(function(index, dragHome) { + thisQ.cloneDragsForOneChoice($(dragHome)); + }); + }; + + /** + * Clone drag item for one choice. + * + * @param {jQuery} dragHome the drag home to clone. + */ + DragDropOntoImageQuestion.prototype.cloneDragsForOneChoice = function(dragHome) { + if (dragHome.hasClass('infinite')) { + var noOfDrags = this.noOfDropsInGroup(this.getGroup(dragHome)); + for (var i = 0; i < noOfDrags; i++) { + this.cloneDrag(dragHome); + } + } else { + this.cloneDrag(dragHome); + } + }; + + /** + * Clone drag item. + * + * @param {jQuery} dragHome + */ + DragDropOntoImageQuestion.prototype.cloneDrag = function(dragHome) { + var drag = dragHome.clone(); + drag.removeClass('draghome') + .addClass('drag unplaced moodle-has-zindex') + .offset(dragHome.offset()); + this.getRoot().find('.dragitems').append(drag); + }; + + /** + * Update the position of drags. + */ + DragDropOntoImageQuestion.prototype.positionDragsAndDrops = function() { + var thisQ = this, + root = this.getRoot(), + bgPosition = this.bgImage().offset(); + + // Move the drops into position. + root.find('.ddarea .dropzone').each(function(i, dropNode) { + var drop = $(dropNode), + place = thisQ.places[thisQ.getPlace(drop)]; + // The xy values come from PHP as strings, so we need parseInt to stop JS doing string concatenation. + drop.offset({ + left: bgPosition.left + parseInt(place.xy[0]), + top: bgPosition.top + parseInt(place.xy[1])}); + }); + + // First move all items back home. + root.find('.ddarea .drag').each(function(i, dragNode) { + var drag = $(dragNode), + currentPlace = thisQ.getClassnameNumericSuffix(drag, 'inplace'); + drag.addClass('unplaced') + .removeClass('placed') + .offset(thisQ.getDragHome(thisQ.getGroup(drag), thisQ.getChoice(drag)).offset()); + if (currentPlace !== null) { + drag.removeClass('inplace' + currentPlace); + } + }); + + // Then place the ones that should be placed. + root.find('input.placeinput').each(function(i, inputNode) { + var input = $(inputNode), + choice = input.val(); + if (choice === '0') { + // No item in this place. + return; + } + + var place = thisQ.getPlace(input); + thisQ.getUnplacedChoice(thisQ.getGroup(input), choice) + .removeClass('unplaced') + .addClass('placed inplace' + place) + .offset(root.find('.dropzone.place' + place).offset()); + }); + }; + + /** + * Handles the start of dragging an item. + * + * @param {Event} e the touch start or mouse down event. + */ + DragDropOntoImageQuestion.prototype.handleDragStart = function(e) { + var thisQ = this, + drag = $(e.target).closest('.drag'); + + var info = dragDrop.prepare(e); + if (!info.start) { + return; + } + + var currentPlace = this.getClassnameNumericSuffix(drag, 'inplace'); + if (currentPlace !== null) { + this.setInputValue(currentPlace, 0); + drag.removeClass('inplace' + currentPlace); + } + + drag.addClass('beingdragged'); + dragDrop.start(e, drag, function(x, y, drag) { + thisQ.dragMove(x, y, drag); + }, function(x, y, drag) { + thisQ.dragEnd(x, y, drag); + }); + }; + + /** + * Called whenever the currently dragged items moves. + * + * @param {Number} pageX the x position. + * @param {Number} pageY the y position. + * @param {jQuery} drag the item being moved. + */ + DragDropOntoImageQuestion.prototype.dragMove = function(pageX, pageY, drag) { + var thisQ = this; + this.getRoot().find('.dropzone.group' + this.getGroup(drag)).each(function(i, dropNode) { + var drop = $(dropNode); + if (thisQ.isPointInDrop(pageX, pageY, drop)) { + drop.addClass('valid-drag-over-drop'); + } else { + drop.removeClass('valid-drag-over-drop'); + } + }); + }; + + /** + * Called when user drops a drag item. + * + * @param {Number} pageX the x position. + * @param {Number} pageY the y position. + * @param {jQuery} drag the item being moved. + */ + DragDropOntoImageQuestion.prototype.dragEnd = function(pageX, pageY, drag) { + var thisQ = this, + root = this.getRoot(), + placed = false; + root.find('.dropzone.group' + this.getGroup(drag)).each(function(i, dropNode) { + var drop = $(dropNode); + if (!thisQ.isPointInDrop(pageX, pageY, drop)) { + // Not this drop. + return true; + } + + // Now put this drag into the drop. + drop.removeClass('valid-drag-over-drop'); + thisQ.sendDragToDrop(drag, drop); + placed = true; + return false; // Stop the each() here. + }); + + if (!placed) { + this.sendDragHome(drag); + } + }; + + /** + * Animate a drag item into a given place (or back home). + * + * @param {jQuery|null} drag the item to place. If null, clear the place. + * @param {jQuery} drop the place to put it. + */ + DragDropOntoImageQuestion.prototype.sendDragToDrop = function(drag, drop) { + // Is there already a drag in this drop? if so, evict it. + var oldDrag = this.getCurrentDragInPlace(this.getPlace(drop)); + if (oldDrag.length !== 0) { + this.sendDragHome(oldDrag); + } + + if (drag.length === 0) { + this.setInputValue(this.getPlace(drop), 0); + } else { + this.setInputValue(this.getPlace(drop), this.getChoice(drag)); + drag.removeClass('unplaced') + .addClass('placed inplace' + this.getPlace(drop)); + this.animateTo(drag, drop); + } + }; + + /** + * Animate a drag back to its home. + * + * @param {jQuery} drag the item being moved. + */ + DragDropOntoImageQuestion.prototype.sendDragHome = function(drag) { + drag.removeClass('placed').addClass('unplaced'); + var currentPlace = this.getClassnameNumericSuffix(drag, 'inplace'); + if (currentPlace !== null) { + drag.removeClass('inplace' + currentPlace); + } + + this.animateTo(drag, this.getDragHome(this.getGroup(drag), this.getChoice(drag))); + }; + + /** + * Handles keyboard events on drops. + * + * Drops are focusable. Once focused, right/down/space switches to the next choice, and + * left/up switches to the previous. Escape clear. + * + * @param {KeyboardEvent} e + */ + DragDropOntoImageQuestion.prototype.handleKeyPress = function(e) { + var drop = $(e.target).closest('.dropzone'), + currentDrag = this.getCurrentDragInPlace(this.getPlace(drop)), + nextDrag = $(); + + switch (e.keyCode) { + case keys.space: + case keys.arrowRight: + case keys.arrowDown: + nextDrag = this.getNextDrag(this.getGroup(drop), currentDrag); + break; + + case keys.arrowLeft: + case keys.arrowUp: + nextDrag = this.getPreviousDrag(this.getGroup(drop), currentDrag); + break; + + case keys.escape: + break; + + default: + return; // To avoid the preventDefault below. + } + + e.preventDefault(); + this.sendDragToDrop(nextDrag, drop); + }; + + /** + * Choose the next drag in a group. + * + * @param {int} group which group. + * @param {jQuery} drag current choice (empty jQuery if there isn't one). + * @return {jQuery} the next drag in that group, or null if there wasn't one. + */ + DragDropOntoImageQuestion.prototype.getNextDrag = function(group, drag) { + var choice, + numChoices = this.noOfChoicesInGroup(group); + + if (drag.length === 0) { + choice = 1; // Was empty, so we want to select the first choice. + } else { + choice = this.getChoice(drag) + 1; + } + + var next = this.getUnplacedChoice(group, choice); + while (next.length === 0 && choice < numChoices) { + choice++; + next = this.getUnplacedChoice(group, choice); + } + + return next; + }; + + /** + * Choose the previous drag in a group. + * + * @param {int} group which group. + * @param {jQuery} drag current choice (empty jQuery if there isn't one). + * @return {jQuery} the next drag in that group, or null if there wasn't one. + */ + DragDropOntoImageQuestion.prototype.getPreviousDrag = function(group, drag) { + var choice; + + if (drag.length === 0) { + choice = this.noOfChoicesInGroup(group); + } else { + choice = this.getChoice(drag) - 1; + } + + var previous = this.getUnplacedChoice(group, choice); + while (previous.length === 0 && choice > 1) { + choice--; + previous = this.getUnplacedChoice(group, choice); + } + + // Does this choice exist? + return previous; + }; + + /** + * Animate an object to the given destination. + * + * @param {jQuery} drag the element to be animated. + * @param {jQuery} target element marking the place to move it to. + */ + DragDropOntoImageQuestion.prototype.animateTo = function(drag, target) { + var currentPos = drag.offset(), + targetPos = target.offset(); + drag.addClass('beingdragged'); + + // Animate works in terms of CSS position, whereas locating an object + // on the page works best with jQuery offset() function. So, to get + // the right target position, we work out the required change in + // offset() and then add that to the current CSS position. + drag.animate( + { + left: parseInt(drag.css('left')) + targetPos.left - currentPos.left, + top: parseInt(drag.css('top')) + targetPos.top - currentPos.top + }, + { + duration: 'fast', + done: function() { + drag.removeClass('beingdragged'); + // It seems that the animation sometimes leaves the drag + // one pixel out of position. Put it in exactly the right place. + drag.offset(targetPos); + } + } + ); + }; + + /** + * Detect if a point is inside a given DOM node. + * + * @param {Number} pageX the x position. + * @param {Number} pageY the y position. + * @param {jQuery} drop the node to check (typically a drop). + * @return {boolean} whether the point is inside the node. + */ + DragDropOntoImageQuestion.prototype.isPointInDrop = function(pageX, pageY, drop) { + var position = drop.offset(); + return pageX >= position.left && pageX < position.left + drop.width() + && pageY >= position.top && pageY < position.top + drop.height(); + }; + + /** + * Set the value of the hidden input for a place, to record what is currently there. + * + * @param {int} place which place to set the input value for. + * @param {int} choice the value to set. + */ + DragDropOntoImageQuestion.prototype.setInputValue = function(place, choice) { + this.getRoot().find('input.placeinput.place' + place).val(choice); + }; + + /** + * Get the outer div for this question. + * + * @returns {jQuery} containing that div. + */ + DragDropOntoImageQuestion.prototype.getRoot = function() { + return $(document.getElementById(this.containerId)); + }; + + /** + * Get the img that is the background image. + * @returns {jQuery} containing that img. + */ + DragDropOntoImageQuestion.prototype.bgImage = function() { + return this.getRoot().find('img.dropbackground'); + }; + + /** + * Get drag home for a given choice. + * + * @param {int} group the group. + * @param {int} choice the choice number. + * @returns {jQuery} containing that div. + */ + DragDropOntoImageQuestion.prototype.getDragHome = function(group, choice) { + return this.getRoot().find('.ddarea .draghome.group' + group + '.choice' + choice); + }; + + /** + * Get an unplaced choice for a particular group. + * + * @param {int} group the group. + * @param {int} choice the choice number. + * @returns {jQuery} jQuery wrapping the unplaced choice. If there isn't one, the jQuery will be empty. + */ + DragDropOntoImageQuestion.prototype.getUnplacedChoice = function(group, choice) { + return this.getRoot().find('.ddarea .drag.group' + group + '.choice' + choice + '.unplaced').slice(0, 1); + }; + + /** + * Get the drag that is currently in a given place. + * + * @param {int} place the place number. + * @return {jQuery} the current drag (or an empty jQuery if none). + */ + DragDropOntoImageQuestion.prototype.getCurrentDragInPlace = function(place) { + return this.getRoot().find('.ddarea .drag.inplace' + place); + }; + + /** + * Return the number of blanks in a given group. + * + * @param {int} group the group number. + * @returns {int} the number of drops. + */ + DragDropOntoImageQuestion.prototype.noOfDropsInGroup = function(group) { + return this.getRoot().find('.dropzone.group' + group).length; + }; + + /** + * Return the number of choices in a given group. + * + * @param {int} group the group number. + * @returns {int} the number of choices. + */ + DragDropOntoImageQuestion.prototype.noOfChoicesInGroup = function(group) { + return this.getRoot().find('.dragitemgroup' + group + ' .draghome').length; + }; + + /** + * Return the number at the end of the CSS class name with the given prefix. + * + * @param {jQuery} node + * @param {String} prefix name prefix + * @returns {Number|null} the suffix if found, else null. + */ + DragDropOntoImageQuestion.prototype.getClassnameNumericSuffix = function(node, prefix) { + var classes = node.attr('class'); + if (classes !== '') { + var classesArr = classes.split(' '); + for (var index = 0; index < classesArr.length; index++) { + var patt1 = new RegExp('^' + prefix + '([0-9])+$'); + if (patt1.test(classesArr[index])) { + var patt2 = new RegExp('([0-9])+$'); + var match = patt2.exec(classesArr[index]); + return Number(match[0]); + } + } + } + return null; + }; + + /** + * Get the choice number of a drag. + * + * @param {jQuery} drag the drag. + * @returns {Number} the choice number. + */ + DragDropOntoImageQuestion.prototype.getChoice = function(drag) { + return this.getClassnameNumericSuffix(drag, 'choice'); + }; + + /** + * Given a DOM node that is significant to this question + * (drag, drop, ...) get the group it belongs to. + * + * @param {jQuery} node a DOM node. + * @returns {Number} the group it belongs to. + */ + DragDropOntoImageQuestion.prototype.getGroup = function(node) { + return this.getClassnameNumericSuffix(node, 'group'); + }; + + /** + * Get the place number of a drop, or its corresponding hidden input. + * + * @param {jQuery} node the DOM node. + * @returns {Number} the place number. + */ + DragDropOntoImageQuestion.prototype.getPlace = function(node) { + return this.getClassnameNumericSuffix(node, 'place'); + }; + + /** + * Singleton object that handles all the DragDropOntoImageQuestions + * on the page, and deals with event dispatching. + * @type {Object} + */ + var questionManager = { + + /** + * {boolean} ensures that the event handlers are only initialised once per page. + */ + eventHandlersInitialised: false, + + /** + * {Object} all the questions on this page, indexed by containerId (id on the .que div). + */ + questions: {}, // An object containing all the information about each question on the page. + + /** + * Initialise one question. + * + * @param {String} containerId the id of the div.que that contains this question. + * @param {boolean} readOnly whether the question is read-only. + * @param {Array} places data. + */ + init: function(containerId, readOnly, places) { + questionManager.questions[containerId] = + new DragDropOntoImageQuestion(containerId, readOnly, places); + if (!questionManager.eventHandlersInitialised) { + questionManager.setupEventHandlers(); + questionManager.eventHandlersInitialised = true; + } + }, + + /** + * Set up the event handlers that make this question type work. (Done once per page.) + */ + setupEventHandlers: function() { + $('body') + .on('mousedown touchstart', + '.que.ddimageortext:not(.qtype_ddimageortext-readonly) .dragitems .drag', + questionManager.handleDragStart) + .on('keydown', + '.que.ddimageortext:not(.qtype_ddimageortext-readonly) .dropzones .dropzone', + questionManager.handleKeyPress); + $(window).on('resize', questionManager.handleWindowResize); + }, + + /** + * Handle mouse down / touch start events on drags. + * @param {Event} e the DOM event. + */ + handleDragStart: function(e) { + e.preventDefault(); + var question = questionManager.getQuestionForEvent(e); + if (question) { + question.handleDragStart(e); + } + }, + + /** + * Handle key down / press events on drags. + * @param {KeyboardEvent} e + */ + handleKeyPress: function(e) { + var question = questionManager.getQuestionForEvent(e); + if (question) { + question.handleKeyPress(e); + } + }, + + /** + * Handle when the window is resized. + */ + handleWindowResize: function() { + for (var containerId in questionManager.questions) { + if (questionManager.questions.hasOwnProperty(containerId)) { + questionManager.questions[containerId].positionDragsAndDrops(); + } + } + }, + + /** + * Given an event, work out which question it effects. + * @param {Event} e the event. + * @returns {DragDropOntoImageQuestion|undefined} The question, or undefined. + */ + getQuestionForEvent: function(e) { + var containerId = $(e.currentTarget).closest('.que.ddimageortext').attr('id'); + return questionManager.questions[containerId]; + } + }; + + /** + * @alias module:qtype_ddimageortext/question + */ + return { + /** + * Initialise one drag-drop onto image question. + * + * @param {String} containerId id of the outer div for this question. + * @param {boolean} readOnly whether the question is being displayed read-only. + * @param {Array} Information about the drop places. + */ + init: questionManager.init + }; +}); diff --git a/question/type/ddimageortext/edit_ddimageortext_form.php b/question/type/ddimageortext/edit_ddimageortext_form.php index 0a733ce707f34..62edd6dec51c3 100644 --- a/question/type/ddimageortext/edit_ddimageortext_form.php +++ b/question/type/ddimageortext/edit_ddimageortext_form.php @@ -108,20 +108,17 @@ public function data_preprocessing($question) { public function js_call() { global $PAGE; - $maxsizes = new stdClass(); - $maxsizes->bgimage = new stdClass(); - $maxsizes->bgimage->width = QTYPE_DDIMAGEORTEXT_BGIMAGE_MAXWIDTH; - $maxsizes->bgimage->height = QTYPE_DDIMAGEORTEXT_BGIMAGE_MAXHEIGHT; - $maxsizes->dragimage = new stdClass(); - $maxsizes->dragimage->width = QTYPE_DDIMAGEORTEXT_DRAGIMAGE_MAXWIDTH; - $maxsizes->dragimage->height = QTYPE_DDIMAGEORTEXT_DRAGIMAGE_MAXHEIGHT; - - $params = array('maxsizes' => $maxsizes, - 'topnode' => 'fieldset#id_previewareaheader'); - - $PAGE->requires->yui_module('moodle-qtype_ddimageortext-form', - 'M.qtype_ddimageortext.init_form', - array($params)); + + $maxbgimagesize = [ + 'width' => QTYPE_DDIMAGEORTEXT_BGIMAGE_MAXWIDTH, + 'height' => QTYPE_DDIMAGEORTEXT_BGIMAGE_MAXHEIGHT + ]; + $maxdragimagesize = [ + 'width' => QTYPE_DDIMAGEORTEXT_DRAGIMAGE_MAXWIDTH, + 'height' => QTYPE_DDIMAGEORTEXT_DRAGIMAGE_MAXHEIGHT + ]; + $PAGE->requires->js_call_amd('qtype_ddimageortext/form', 'init', + [$maxbgimagesize, $maxdragimagesize]); } // Drag items. @@ -166,7 +163,7 @@ protected function draggable_item($mform) { $draggableimageitem[] = $mform->createElement('text', 'draglabel', get_string('label', 'qtype_ddimageortext'), - array('size' => 30, 'class' => 'tweakcss')); + array('size' => 30, 'class' => 'tweakcss draglabel')); $mform->setType('draglabel', PARAM_RAW); // These are validated manually. return $draggableimageitem; } diff --git a/question/type/ddimageortext/rendererbase.php b/question/type/ddimageortext/rendererbase.php index 58bca8546f858..9d1f779b22f26 100644 --- a/question/type/ddimageortext/rendererbase.php +++ b/question/type/ddimageortext/rendererbase.php @@ -66,8 +66,9 @@ public function formulation_and_controls(question_attempt $qa, $img = html_writer::empty_tag('img', array( 'src' => $bgimage, 'class' => 'dropbackground', 'alt' => get_string('dropbackground', 'qtype_ddimageortext'))); + $dropzones = html_writer::tag('div', '', array('class' => 'dropzones')); - $droparea = html_writer::tag('div', $img, array('class' => 'droparea')); + $droparea = html_writer::tag('div', $img . $dropzones, array('class' => 'droparea')); $dragimagehomes = ''; foreach ($question->choices as $groupno => $group) { @@ -77,13 +78,11 @@ public function formulation_and_controls(question_attempt $qa, $dragimageurl = self::get_url_for_image($qa, 'dragimage', $dragimage->id); $classes = array("group{$groupno}", 'draghome', - "dragitemhomes{$dragimage->no}", "choice{$choiceno}"); if ($dragimage->infinite) { $classes[] = 'infinite'; } if ($dragimageurl === null) { - $classes[] = 'yui3-cssfonts'; $dragimagehomesgroup .= html_writer::tag('div', $dragimage->text, array('src' => $dragimageurl, 'class' => join(' ', $classes))); } else { @@ -96,31 +95,27 @@ public function formulation_and_controls(question_attempt $qa, array('class' => 'dragitemgroup' . $groupno)); } + $draghomes = html_writer::tag('div', $dragimagehomes, array('class' => 'draghomes')); $dragitemsclass = 'dragitems'; if ($options->readonly) { $dragitemsclass .= ' readonly'; } - $dragitems = html_writer::tag('div', $dragimagehomes, array('class' => $dragitemsclass)); - $dropzones = html_writer::tag('div', '', array('class' => 'dropzones')); + $dragitems = html_writer::tag('div', '', array('class' => $dragitemsclass)); $hiddens = ''; foreach ($question->places as $placeno => $place) { $varname = $question->field($placeno); - list($fieldname, $html) = $this->hidden_field_for_qt_var($qa, $varname); + list($fieldname, $html) = $this->hidden_field_for_qt_var($qa, $varname, null, + ['placeinput', 'place' . $placeno, 'group' . $place->group]); $hiddens .= $html; $question->places[$placeno]->fieldname = $fieldname; } $output .= html_writer::tag('div', - $droparea . $dragitems . $dropzones . $hiddens, array('class' => 'ddarea')); - $topnode = 'div#q'.$qa->get_slot().' div.ddarea'; - $params = array('drops' => $question->places, - 'topnode' => $topnode, - 'readonly' => $options->readonly); + $droparea . $draghomes. $dragitems . $hiddens, array('class' => 'ddarea')); $PAGE->requires->string_for_js('blank', 'qtype_ddimageortext'); - $PAGE->requires->yui_module('moodle-qtype_ddimageortext-dd', - 'M.qtype_ddimageortext.init_question', - array($params)); + $PAGE->requires->js_call_amd('qtype_ddimageortext/question', 'init', + ['q' . $qa->get_slot(), $options->readonly, $question->places]); if ($qa->get_state() == question_state::$invalid) { $output .= html_writer::nonempty_tag('div', diff --git a/question/type/ddimageortext/styles.css b/question/type/ddimageortext/styles.css index bce4d90e1cc35..5ae690a837409 100644 --- a/question/type/ddimageortext/styles.css +++ b/question/type/ddimageortext/styles.css @@ -3,28 +3,73 @@ display: block; } -.que.ddimageortext div.droparea img, -form.mform fieldset#id_previewareaheader div.droparea img { +.que.ddimageortext div.ddarea, +form.mform fieldset#id_previewareaheader div.ddarea { + text-align: center; +} + +.que.ddimageortext div.droparea, +form.mform fieldset#id_previewareaheader div.ddarea { + position: relative; +} + +.que.ddimageortext .dropbackground, +form.mform fieldset#id_previewareaheader .dropbackground { border: 1px solid #000; max-width: none; + margin: 0 auto; +} + +.que.ddimageortext .dropzone { + position: absolute; + opacity: 0.5; + border: 1px solid black; + z-index: 1; +} + +.que.ddimageortext .dropzone:focus, +.que.ddimageortext .dropzone.valid-drag-over-drop { + border-color: #0a0; + box-shadow: 0 0 5px 5px rgba(255, 255, 150, 1); + outline: 0; } .que.ddimageortext .draghome, -form.mform fieldset#id_previewareaheader .draghome { +.que.ddimageortext .drag, +form.mform fieldset#id_previewareaheader .droppreview { + border: 1px solid black; + display: inline-block; + font: 13px/1.231 arial, helvetica, clean, sans-serif; +} + +.que.ddimageortext .draghome { vertical-align: top; margin: 5px; visibility: hidden; + height: auto; + width: auto; } -.que.ddimageortext div.draghome, -form.mform fieldset#id_previewareaheader div.draghome { - border: 1px solid black; +.que.ddimageortext .dragitems, +form.mform fieldset#id_previewareaheader .dragitems { + height: 0; +} + +.que.ddimageortext .drag, +form.mform fieldset#id_previewareaheader .droppreview { + position: absolute; cursor: move; - background-color: #b0c4de; - display: inline-block; - height: auto; - width: auto; - zoom: 1; + z-index: 2; +} + +.que.ddimageortext .dragitems.readonly .drag { + cursor: auto; +} + +form.mform fieldset#id_previewareaheader .drag.beingdragged, +.que.ddimageortext .drag.beingdragged { + z-index: 3; + box-shadow: 3px 3px 4px #000; } .que.ddimageortext .group1, @@ -67,51 +112,6 @@ form.mform fieldset#id_previewareaheader .group8 { background-color: #f0e68c; } -.que.ddimageortext .drag, -form.mform fieldset#id_previewareaheader .drag { - border: 1px solid black; - cursor: move; - z-index: 2; -} - -.que.ddimageortext .dragitems.readonly .drag { - cursor: auto; -} - -.que.ddimageortext div.ddarea, -form.mform fieldset#id_previewareaheader div.ddarea { - text-align: center; -} - -.que.ddimageortext .dropbackground, -form.mform fieldset#id_previewareaheader .dropbackground { - margin: 0 auto; -} - -.que.ddimageortext .dropzone { - border: 1px solid black; - position: absolute; - z-index: 1; -} - -.que.ddimageortext .dropzone:focus, -.que.ddimageortext .dropzone.yui3-dd-drop-over.yui3-dd-drop-active-valid { - border-color: #0a0; - box-shadow: 0 0 5px 5px rgba(255, 255, 150, 1); -} - -.que.ddimageortext div.dragitems div.draghome, -.que.ddimageortext div.dragitems div.drag, -form.mform fieldset#id_previewareaheader div.draghome, -form.mform fieldset#id_previewareaheader div.drag { - font: 13px/1.231 arial, helvetica, clean, sans-serif; -} - -form.mform fieldset#id_previewareaheader div.drag.yui3-dd-dragging, -.que.ddimageortext div.drag.yui3-dd-dragging { - z-index: 3; - box-shadow: 3px 3px 4px #000; -} /* Editing form. Style repeated elements*/ /*Top*/ body#page-question-type-ddimageortext div[id^=fgroup_id_][id*=drags_] { diff --git a/question/type/ddimageortext/tests/behat/behat_qtype_ddimageortext.php b/question/type/ddimageortext/tests/behat/behat_qtype_ddimageortext.php index 15c38801d6b7e..ac893d482e022 100644 --- a/question/type/ddimageortext/tests/behat/behat_qtype_ddimageortext.php +++ b/question/type/ddimageortext/tests/behat/behat_qtype_ddimageortext.php @@ -41,7 +41,8 @@ class behat_qtype_ddimageortext extends behat_base { * @return string the xpath expression. */ protected function drag_xpath($dragitem) { - return '//div[contains(@class, " drag ") and contains(normalize-space(.), "' . $this->escape($dragitem) . '")]'; + return '//div[contains(concat(" ", @class, " "), " drag ") and ' . + 'contains(normalize-space(.), "' . $this->escape($dragitem) . '")]'; } /** @@ -50,7 +51,8 @@ protected function drag_xpath($dragitem) { * @return string the xpath expression. */ protected function drop_xpath($placenumber) { - return '//div[contains(@class, "dropzone ") and contains(@class, "place' . $placenumber . ' ")]'; + return '//div[contains(concat(" ", @class, " "), " dropzone ") and ' . + 'contains(concat(" ", @class, " "), " place' . $placenumber . ' ")]'; } /** diff --git a/question/type/ddimageortext/tests/behat/preview.feature b/question/type/ddimageortext/tests/behat/preview.feature index b1d78728e05b6..eac31a37f465b 100644 --- a/question/type/ddimageortext/tests/behat/preview.feature +++ b/question/type/ddimageortext/tests/behat/preview.feature @@ -30,7 +30,7 @@ Feature: Preview a drag-drop onto image question And I switch to "questionpreview" window # Increase window size and wait 2 seconds to ensure elements are placed properly by js. # Keep window large else drag will scroll the window to find element. - And I change window size to "large" + And I change window size to "medium" And I wait "2" seconds # Odd, but the
s go to nothing, not a space. And I drag "mountainbelt" to place "1" in the drag and drop onto image question @@ -51,7 +51,7 @@ Feature: Preview a drag-drop onto image question When I click on "Preview" "link" in the "Drag onto image" "table_row" And I switch to "questionpreview" window # Increase window size and wait 2 seconds to ensure elements are placed properly by js. - And I change window size to "large" + And I change window size to "medium" And I wait "2" seconds And I type " " on place "1" in the drag and drop onto image question And I type " " on place "2" in the drag and drop onto image question diff --git a/question/type/ddimageortext/tests/walkthrough_test.php b/question/type/ddimageortext/tests/walkthrough_test.php index 932ac1bce3419..e9cad591782e2 100644 --- a/question/type/ddimageortext/tests/walkthrough_test.php +++ b/question/type/ddimageortext/tests/walkthrough_test.php @@ -46,8 +46,7 @@ class qtype_ddimageortext_walkthrough_test extends qbehaviour_walkthrough_test_b * @return question_contains_tag_with_attributes the required expectation. */ protected function get_contains_drag_image_home_expectation($dragitemno, $choice, $group) { - $class = 'group' . $group; - $class .= ' draghome dragitemhomes' . $dragitemno. ' choice'.$choice.' yui3-cssfonts'; + $class = 'group' . $group . ' draghome choice' . $choice; $expectedattrs = array(); $expectedattrs['class'] = $class; diff --git a/question/type/ddimageortext/yui/build/moodle-qtype_ddimageortext-dd/moodle-qtype_ddimageortext-dd-debug.js b/question/type/ddimageortext/yui/build/moodle-qtype_ddimageortext-dd/moodle-qtype_ddimageortext-dd-debug.js deleted file mode 100644 index 022e28e35caf0..0000000000000 --- a/question/type/ddimageortext/yui/build/moodle-qtype_ddimageortext-dd/moodle-qtype_ddimageortext-dd-debug.js +++ /dev/null @@ -1,546 +0,0 @@ -YUI.add('moodle-qtype_ddimageortext-dd', function (Y, NAME) { - -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -var DDIMAGEORTEXTDDNAME = 'ddimageortext_dd'; -var DDIMAGEORTEXT_DD = function() { - DDIMAGEORTEXT_DD.superclass.constructor.apply(this, arguments); -}; - -/** - * This is the base class for the question rendering and question editing form code. - */ -Y.extend(DDIMAGEORTEXT_DD, Y.Base, { - doc: null, - polltimer: null, - afterimageloaddone: false, - poll_for_image_load: function(e, waitforimageconstrain, pause, doafterwords) { - if (this.afterimageloaddone) { - return; - } - var bgdone = this.doc.bg_img().get('complete'); - if (waitforimageconstrain) { - bgdone = bgdone && this.doc.bg_img().hasClass('constrained'); - } - var alldragsloaded = !this.doc.drag_item_homes().some(function(dragitemhome) { - // in 'some' loop returning true breaks the loop and is passed as return value from - // 'some' else returns false. Can be though of as equivalent to ||. - if (dragitemhome.get('tagName') !== 'IMG') { - return false; - } - var done = (dragitemhome.get('complete')); - if (waitforimageconstrain) { - done = done && dragitemhome.hasClass('constrained'); - } - return !done; - }); - if (bgdone && alldragsloaded) { - if (this.polltimer !== null) { - this.polltimer.cancel(); - this.polltimer = null; - } - this.doc.drag_item_homes().detach('load', this.poll_for_image_load); - this.doc.bg_img().detach('load', this.poll_for_image_load); - if (pause !== 0) { - Y.later(pause, this, doafterwords); - } else { - doafterwords.call(this); - } - this.afterimageloaddone = true; - } else if (this.polltimer === null) { - var pollarguments = [null, waitforimageconstrain, pause, doafterwords]; - this.polltimer = - Y.later(1000, this, this.poll_for_image_load, pollarguments, true); - } - }, - /** - * Object to encapsulate operations on dd area. - */ - doc_structure: function(mainobj) { - var topnode = Y.one(this.get('topnode')); - var dragitemsarea = topnode.one('div.dragitems'); - var dropbgarea = topnode.one('div.droparea'); - return { - top_node: function() { - return topnode; - }, - drag_items: function() { - return dragitemsarea.all('.drag'); - }, - drop_zones: function() { - return topnode.all('div.dropzones div.dropzone'); - }, - drop_zone_group: function(groupno) { - return topnode.all('div.dropzones div.group' + groupno); - }, - drag_items_cloned_from: function(dragitemno) { - return dragitemsarea.all('.dragitems' + dragitemno); - }, - drag_item: function(draginstanceno) { - return dragitemsarea.one('.draginstance' + draginstanceno); - }, - drag_items_in_group: function(groupno) { - return dragitemsarea.all('.drag.group' + groupno); - }, - drag_item_homes: function() { - return dragitemsarea.all('.draghome'); - }, - bg_img: function() { - return topnode.one('.dropbackground'); - }, - load_bg_img: function(url) { - dropbgarea.setContent(''); - this.bg_img().on('load', this.on_image_load, this, 'bg_image'); - }, - add_or_update_drag_item_home: function(dragitemno, url, alt, group) { - var oldhome = this.drag_item_home(dragitemno); - var classes = 'draghome dragitemhomes' + dragitemno + ' group' + group; - var imghtml = '' + alt + ''; - var divhtml = '
' + alt + '
'; - if (oldhome === null) { - if (url) { - dragitemsarea.append(imghtml); - } else if (alt !== '') { - dragitemsarea.append(divhtml); - } - } else { - if (url) { - dragitemsarea.insert(imghtml, oldhome); - } else if (alt !== '') { - dragitemsarea.insert(divhtml, oldhome); - } - oldhome.remove(true); - } - var newlycreated = dragitemsarea.one('.dragitemhomes' + dragitemno); - if (newlycreated !== null) { - newlycreated.setData('groupno', group); - newlycreated.setData('dragitemno', dragitemno); - } - }, - drag_item_home: function(dragitemno) { - return dragitemsarea.one('.dragitemhomes' + dragitemno); - }, - get_classname_numeric_suffix: function(node, prefix) { - var classes = node.getAttribute('class'); - if (classes !== '') { - var classesarr = classes.split(' '); - for (var index = 0; index < classesarr.length; index++) { - var patt1 = new RegExp('^' + prefix + '([0-9])+$'); - if (patt1.test(classesarr[index])) { - var patt2 = new RegExp('([0-9])+$'); - var match = patt2.exec(classesarr[index]); - return +match[0]; - } - } - } - throw 'Prefix "' + prefix + '" not found in class names.'; - }, - clone_new_drag_item: function(draginstanceno, dragitemno) { - var draghome = this.drag_item_home(dragitemno); - if (draghome === null) { - return null; - } - var drag = draghome.cloneNode(true); - drag.removeClass('dragitemhomes' + dragitemno); - drag.addClass('dragitems' + dragitemno); - drag.addClass('draginstance' + draginstanceno); - drag.removeClass('draghome'); - drag.addClass('drag'); - drag.setStyles({'visibility': 'visible', 'position': 'absolute'}); - drag.setData('draginstanceno', draginstanceno); - drag.setData('dragitemno', dragitemno); - draghome.get('parentNode').appendChild(drag); - return drag; - }, - draggable_for_question: function(drag, group, choice) { - new Y.DD.Drag({ - node: drag, - dragMode: 'point', - groups: [group] - }).plug(Y.Plugin.DDConstrained, {constrain2node: topnode}); - - drag.setData('group', group); - drag.setData('choice', choice); - }, - draggable_for_form: function(drag) { - var dd = new Y.DD.Drag({ - node: drag, - dragMode: 'point' - }).plug(Y.Plugin.DDConstrained, {constrain2node: topnode}); - dd.on('drag:end', function(e) { - var dragnode = e.target.get('node'); - var draginstanceno = dragnode.getData('draginstanceno'); - var gooddrop = dragnode.getData('gooddrop'); - - if (!gooddrop) { - mainobj.reset_drag_xy(draginstanceno); - } else { - mainobj.set_drag_xy(draginstanceno, [e.pageX, e.pageY]); - } - }, this); - dd.on('drag:start', function(e) { - var drag = e.target; - drag.get('node').setData('gooddrop', false); - }, this); - - } - - }; - }, - - update_padding_sizes_all: function() { - for (var groupno = 1; groupno <= 8; groupno++) { - this.update_padding_size_for_group(groupno); - } - }, - update_padding_size_for_group: function(groupno) { - var groupitems = this.doc.top_node().all('.draghome.group' + groupno); - if (groupitems.size() !== 0) { - var maxwidth = 0; - var maxheight = 0; - groupitems.each(function(item) { - maxwidth = Math.max(maxwidth, item.get('clientWidth')); - maxheight = Math.max(maxheight, item.get('clientHeight')); - }, this); - groupitems.each(function(item) { - var margintopbottom = Math.round((10 + maxheight - item.get('clientHeight')) / 2); - var marginleftright = Math.round((10 + maxwidth - item.get('clientWidth')) / 2); - item.setStyle('padding', margintopbottom + 'px ' + marginleftright + 'px ' + - margintopbottom + 'px ' + marginleftright + 'px'); - }, this); - this.doc.drop_zone_group(groupno).setStyles({'width': maxwidth + 10, - 'height': maxheight + 10}); - } - }, - convert_to_window_xy: function(bgimgxy) { - return [Number(bgimgxy[0]) + this.doc.bg_img().getX() + 1, - Number(bgimgxy[1]) + this.doc.bg_img().getY() + 1]; - } -}, { - NAME: DDIMAGEORTEXTDDNAME, - ATTRS: { - drops: {value: null}, - readonly: {value: false}, - topnode: {value: null} - } -}); - -M.qtype_ddimageortext = M.qtype_ddimageortext || {}; -M.qtype_ddimageortext.dd_base_class = DDIMAGEORTEXT_DD; - -var DDIMAGEORTEXTQUESTIONNAME = 'ddimageortext_question'; -var DDIMAGEORTEXT_QUESTION = function() { - DDIMAGEORTEXT_QUESTION.superclass.constructor.apply(this, arguments); -}; -/** - * This is the code for question rendering. - */ -Y.extend(DDIMAGEORTEXT_QUESTION, M.qtype_ddimageortext.dd_base_class, { - passiveSupported: false, - pendingid: '', - initializer: function() { - this.pendingid = 'qtype_ddimageortext-' + Math.random().toString(36).slice(2); // Random string. - M.util.js_pending(this.pendingid); - this.doc = this.doc_structure(this); - this.poll_for_image_load(null, false, 10, this.create_all_drag_and_drops); - this.doc.bg_img().after('load', this.poll_for_image_load, this, - false, 10, this.create_all_drag_and_drops); - this.doc.drag_item_homes().after('load', this.poll_for_image_load, this, - false, 10, this.create_all_drag_and_drops); - if (!this.get('readonly')) { - Y.later(500, this, this.reposition_drags_for_question, true); - } else { - Y.one('window').on('resize', function() { - this.reposition_drags_for_question(); - }, this); - } - this.checkPassiveSupported(); - }, - - /** - * prevent_touchmove_from_scrolling allows users of touch screen devices to - * use drag and drop and normal scrolling at the same time. I.e. when - * touching and dragging a draggable item, the screen does not scroll, but - * you can scroll by touching other area of the screen apart from the - * draggable items. - */ - prevent_touchmove_from_scrolling: function(drag) { - var touchmove = (Y.UA.ie) ? 'MSPointerMove' : 'touchmove'; - var eventHandler = function(event) { - event.preventDefault(); - }; - var dragId = drag.get('id'); - var el = document.getElementById(dragId); - // Note do not dynamically add events within another event, as this causes issues on iOS11.3. - // See https://github.com/atlassian/react-beautiful-dnd/issues/413 and - // https://bugs.webkit.org/show_bug.cgi?id=184250 for fuller explanation. - el.addEventListener(touchmove, eventHandler, this.passiveSupported ? {passive: false, capture: true} : false); - }, - - /** - * Some older browsers do not support passing an options object to addEventListener. - * This is a check from https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener. - */ - checkPassiveSupported: function() { - try { - var options = Object.defineProperty({}, 'passive', { - get: function() { - this.passiveSupported = true; - }.bind(this) - }); - window.addEventListener('test', options, options); - window.removeEventListener('test', options, options); - } catch (err) { - this.passiveSupported = false; - } - }, - - create_all_drag_and_drops: function() { - this.init_drops(); - this.update_padding_sizes_all(); - var i = 0; - this.doc.drag_item_homes().each(function(dragitemhome) { - var dragitemno = Number(this.doc.get_classname_numeric_suffix(dragitemhome, 'dragitemhomes')); - var choice = +this.doc.get_classname_numeric_suffix(dragitemhome, 'choice'); - var group = +this.doc.get_classname_numeric_suffix(dragitemhome, 'group'); - var groupsize = this.doc.drop_zone_group(group).size(); - var dragnode = this.doc.clone_new_drag_item(i, dragitemno); - i++; - if (!this.get('readonly')) { - this.doc.draggable_for_question(dragnode, group, choice); - - // Prevent scrolling whilst dragging on Adroid devices. - this.prevent_touchmove_from_scrolling(dragnode); - } - if (dragnode.hasClass('infinite')) { - var dragstocreate = groupsize - 1; - while (dragstocreate > 0) { - dragnode = this.doc.clone_new_drag_item(i, dragitemno); - i++; - if (!this.get('readonly')) { - this.doc.draggable_for_question(dragnode, group, choice); - - // Prevent scrolling whilst dragging on Adroid devices. - this.prevent_touchmove_from_scrolling(dragnode); - } - dragstocreate--; - } - } - }, this); - this.reposition_drags_for_question(); - if (!this.get('readonly')) { - this.doc.drop_zones().set('tabIndex', 0); - this.doc.drop_zones().each( - function(v) { - v.on('dragchange', this.drop_zone_key_press, this); - }, this); - } - M.util.js_complete(this.pendingid); - }, - drop_zone_key_press: function(e) { - switch (e.direction) { - case 'next' : - this.place_next_drag_in(e.target); - break; - case 'previous' : - this.place_previous_drag_in(e.target); - break; - case 'remove' : - this.remove_drag_from_drop(e.target); - break; - } - e.preventDefault(); - this.reposition_drags_for_question(); - }, - place_next_drag_in: function(drop) { - this.search_for_unplaced_drop_choice(drop, 1); - }, - place_previous_drag_in: function(drop) { - this.search_for_unplaced_drop_choice(drop, -1); - }, - search_for_unplaced_drop_choice: function(drop, direction) { - var next; - var current = this.current_drag_in_drop(drop); - if ('' === current) { - if (direction === 1) { - next = 1; - } else { - next = 1; - var groupno = drop.getData('group'); - this.doc.drag_items_in_group(groupno).each(function(drag) { - next = Math.max(next, drag.getData('choice')); - }, this); - } - } else { - next = +current + direction; - } - var drag; - do { - if (this.get_choices_for_drop(next, drop).size() === 0) { - this.remove_drag_from_drop(drop); - return; - } else { - drag = this.get_unplaced_choice_for_drop(next, drop); - } - next = next + direction; - } while (drag === null); - this.place_drag_in_drop(drag, drop); - }, - current_drag_in_drop: function(drop) { - var inputid = drop.getData('inputid'); - var inputnode = Y.one('input#' + inputid); - return inputnode.get('value'); - }, - remove_drag_from_drop: function(drop) { - this.place_drag_in_drop(null, drop); - }, - place_drag_in_drop: function(drag, drop) { - var inputid = drop.getData('inputid'); - var inputnode = Y.one('input#' + inputid); - if (drag !== null) { - inputnode.set('value', drag.getData('choice')); - } else { - inputnode.set('value', ''); - } - }, - reposition_drags_for_question: function(dotimeout) { - this.doc.drag_items().removeClass('placed'); - this.doc.drag_items().each(function(dragitem) { - if (dragitem.dd !== undefined) { - dragitem.dd.detachAll('drag:start'); - } - }, this); - this.doc.drop_zones().each(function(dropzone) { - var relativexy = dropzone.getData('xy'); - dropzone.setXY(this.convert_to_window_xy(relativexy)); - var inputcss = 'input#' + dropzone.getData('inputid'); - var input = this.doc.top_node().one(inputcss); - var choice = input.get('value'); - if (choice !== "") { - var dragitem = this.get_unplaced_choice_for_drop(choice, dropzone); - if (dragitem !== null) { - dragitem.setXY(dropzone.getXY()); - dragitem.addClass('placed'); - if (dragitem.dd !== undefined) { - dragitem.dd.once('drag:start', function(e, input) { - input.set('value', ''); - e.target.get('node').removeClass('placed'); - }, this, input); - } - } - } - }, this); - this.doc.drag_items().each(function(dragitem) { - if (!dragitem.hasClass('placed') && !dragitem.hasClass('yui3-dd-dragging')) { - var dragitemhome = this.doc.drag_item_home(dragitem.getData('dragitemno')); - dragitem.setXY(dragitemhome.getXY()); - } - }, this); - if (dotimeout) { - Y.later(500, this, this.reposition_drags_for_question, true); - } - }, - get_choices_for_drop: function(choice, drop) { - var group = drop.getData('group'); - return this.doc.top_node().all( - 'div.dragitemgroup' + group + ' .choice' + choice + '.drag'); - }, - get_unplaced_choice_for_drop: function(choice, drop) { - var dragitems = this.get_choices_for_drop(choice, drop); - var dragitem = null; - dragitems.some(function(d) { - if (this.get('readonly') || (!d.hasClass('placed') && !d.hasClass('yui3-dd-dragging'))) { - dragitem = d; - return true; - } else { - return false; - } - }); - return dragitem; - }, - init_drops: function() { - var dropareas = this.doc.top_node().one('div.dropzones'); - var groupnodes = {}; - for (var groupno = 1; groupno <= 8; groupno++) { - var groupnode = Y.Node.create('
'); - dropareas.append(groupnode); - groupnodes[groupno] = groupnode; - } - var drop_hit_handler = function(e) { - var drag = e.drag.get('node'); - var drop = e.drop.get('node'); - if (Number(drop.getData('group')) === drag.getData('group')) { - this.place_drag_in_drop(drag, drop); - } - }; - for (var dropno in this.get('drops')) { - var drop = this.get('drops')[dropno]; - var nodeclass = 'dropzone group' + drop.group + ' place' + dropno; - var title = drop.text.replace('"', '\"'); - if (!title) { - title = M.util.get_string('blank', 'qtype_ddimageortext'); - } - var dropnodehtml = '
' + - '' + title + ' 
'; - var dropnode = Y.Node.create(dropnodehtml); - groupnodes[drop.group].append(dropnode); - dropnode.setStyles({'opacity': 0.5}); - dropnode.setData('xy', drop.xy); - dropnode.setData('place', dropno); - dropnode.setData('inputid', drop.fieldname.replace(':', '_')); - dropnode.setData('group', drop.group); - var dropdd = new Y.DD.Drop({ - node: dropnode, groups: [drop.group]}); - dropdd.on('drop:hit', drop_hit_handler, this); - } - } -}, {NAME: DDIMAGEORTEXTQUESTIONNAME, ATTRS: {}}); - -Y.Event.define('dragchange', { - // Webkit and IE repeat keydown when you hold down arrow keys. - // Opera links keypress to page scroll; others keydown. - // Firefox prevents page scroll via preventDefault() on either - // keydown or keypress. - _event: (Y.UA.webkit || Y.UA.ie) ? 'keydown' : 'keypress', - - _keys: { - '32': 'next', // Space - '37': 'previous', // Left arrow - '38': 'previous', // Up arrow - '39': 'next', // Right arrow - '40': 'next', // Down arrow - '27': 'remove' // Escape - }, - - _keyHandler: function(e, notifier) { - if (this._keys[e.keyCode]) { - e.direction = this._keys[e.keyCode]; - notifier.fire(e); - } - }, - - on: function(node, sub, notifier) { - sub._detacher = node.on(this._event, this._keyHandler, - this, notifier); - } -}); - -M.qtype_ddimageortext.init_question = function(config) { - return new DDIMAGEORTEXT_QUESTION(config); -}; - - -}, '@VERSION@', {"requires": ["node", "dd", "dd-drop", "dd-constrain"]}); diff --git a/question/type/ddimageortext/yui/build/moodle-qtype_ddimageortext-dd/moodle-qtype_ddimageortext-dd-min.js b/question/type/ddimageortext/yui/build/moodle-qtype_ddimageortext-dd/moodle-qtype_ddimageortext-dd-min.js deleted file mode 100644 index f8ab7a6a59aec..0000000000000 --- a/question/type/ddimageortext/yui/build/moodle-qtype_ddimageortext-dd/moodle-qtype_ddimageortext-dd-min.js +++ /dev/null @@ -1,2 +0,0 @@ -YUI.add("moodle-qtype_ddimageortext-dd",function(e,t){var n="ddimageortext_dd",r=function(){r.superclass.constructor.apply(this,arguments)};e.extend(r,e.Base,{doc:null,polltimer:null,afterimageloaddone:!1,poll_for_image_load:function(t,n,r,i){if(this.afterimageloaddone)return;var s=this.doc.bg_img().get("complete");n&&(s=s&&this.doc.bg_img().hasClass("constrained"));var o=!this.doc.drag_item_homes().some(function(e){if(e.get("tagName")!=="IMG")return!1;var t=e.get("complete");return n&&(t=t&&e.hasClass("constrained")),!t});if(s&&o)this.polltimer!==null&&(this.polltimer.cancel(),this.polltimer=null),this.doc.drag_item_homes().detach("load",this.poll_for_image_load),this.doc.bg_img().detach("load",this.poll_for_image_load),r!==0?e.later(r,this,i):i.call(this),this.afterimageloaddone=!0;else if(this.polltimer===null){var u=[null,n,r,i];this.polltimer=e.later(1e3,this,this.poll_for_image_load,u,!0)}},doc_structure:function(t){var n=e.one(this.get("topnode")),r=n.one("div.dragitems"),i=n.one("div.droparea");return{top_node:function(){return n},drag_items:function(){return r.all(".drag")},drop_zones:function(){return n.all("div.dropzones div.dropzone")},drop_zone_group:function(e){return n.all("div.dropzones div.group"+e)},drag_items_cloned_from:function(e){return r.all(".dragitems"+e)},drag_item:function(e){return r.one(".draginstance"+e)},drag_items_in_group:function(e){return r.all(".drag.group"+e)},drag_item_homes:function(){return r.all(".draghome")},bg_img:function(){return n.one(".dropbackground")},load_bg_img:function(e){i.setContent(''),this.bg_img().on("load",this.on_image_load,this,"bg_image")},add_or_update_drag_item_home:function(e,t,n,i){var s=this.drag_item_home(e),o="draghome dragitemhomes"+e+" group"+i,u=''+n+'',a='
'+n+"
";s===null?t?r.append(u):n!==""&&r.append(a):(t?r.insert(u,s):n!==""&&r.insert(a,s),s.remove(!0));var f=r.one(".dragitemhomes"+e);f!==null&&(f.setData("groupno",i),f.setData("dragitemno",e))},drag_item_home:function(e){return r.one(".dragitemhomes"+e)},get_classname_numeric_suffix:function(e,t){var n=e.getAttribute("class");if(n!==""){var r=n.split(" ");for(var i=0;i0)o=this.doc.clone_new_drag_item(e,n),e++,this.get("readonly")||(this.doc.draggable_for_question(o,i,r),this.prevent_touchmove_from_scrolling(o)),u--}},this),this.reposition_drags_for_question(),this.get("readonly")||(this.doc.drop_zones().set("tabIndex",0),this.doc.drop_zones().each(function(e){e.on("dragchange",this.drop_zone_key_press,this)},this)),M.util.js_complete(this.pendingid)},drop_zone_key_press:function(e){switch(e.direction){case"next":this.place_next_drag_in(e.target);break;case"previous":this.place_previous_drag_in(e.target);break;case"remove":this.remove_drag_from_drop(e.target)}e.preventDefault(),this.reposition_drags_for_question()},place_next_drag_in:function(e){this.search_for_unplaced_drop_choice(e,1)},place_previous_drag_in:function(e){this.search_for_unplaced_drop_choice(e,-1)},search_for_unplaced_drop_choice:function(e,t){var n,r=this.current_drag_in_drop(e);if(""===r)if(t===1)n=1;else{n=1;var i=e.getData("group");this.doc.drag_items_in_group(i).each(function(e){n=Math.max(n,e.getData("choice"))},this)}else n=+r+t;var s;do{if(this.get_choices_for_drop(n,e).size()===0){this.remove_drag_from_drop(e);return}s=this.get_unplaced_choice_for_drop(n,e),n+=t}while(s===null);this.place_drag_in_drop(s,e)},current_drag_in_drop:function(t){var n=t.getData("inputid"),r=e.one("input#"+n);return r.get("value")},remove_drag_from_drop:function(e){this.place_drag_in_drop(null,e)},place_drag_in_drop:function(t,n){var r=n.getData("inputid"),i=e.one("input#"+r);t!==null?i.set("value",t.getData("choice")):i.set("value","")},reposition_drags_for_question:function(t){this.doc.drag_items().removeClass("placed"),this.doc.drag_items().each(function(e){e.dd!==undefined&&e.dd.detachAll("drag:start")},this),this.doc.drop_zones().each(function(e){var t=e.getData("xy");e.setXY(this.convert_to_window_xy(t));var n="input#"+e.getData("inputid"),r=this.doc.top_node().one(n),i=r.get("value");if(i!==""){var s=this.get_unplaced_choice_for_drop(i,e);s!==null&&(s.setXY(e.getXY()),s.addClass("placed"),s.dd!==undefined&&s.dd.once("drag:start",function(e,t){t.set("value",""),e.target.get("node").removeClass("placed")},this,r))}},this),this.doc.drag_items().each(function(e){if(!e.hasClass("placed")&&!e.hasClass("yui3-dd-dragging")){var t=this.doc.drag_item_home(e.getData("dragitemno"));e.setXY(t.getXY())}},this),t&&e.later(500,this,this.reposition_drags_for_question,!0)},get_choices_for_drop:function(e,t){var n=t.getData("group");return this.doc.top_node().all("div.dragitemgroup"+n+" .choice"+e+".drag")},get_unplaced_choice_for_drop:function(e,t){var n=this.get_choices_for_drop(e,t),r=null;return n.some(function(e){return this.get("readonly")||!e.hasClass("placed")&&!e.hasClass("yui3-dd-dragging")?(r=e,!0):!1}),r},init_drops:function(){var t=this.doc.top_node().one("div.dropzones"),n={};for(var r=1;r<=8;r++){var i=e.Node.create('
');t.append(i),n[r]=i}var s=function(e){var t=e.drag.get("node"),n=e.drop.get("node");Number(n.getData("group"))===t.getData("group")&&this.place_drag_in_drop(t,n)};for(var o in this.get("drops")){var u=this.get("drops")[o],a="dropzone group"+u.group+" place"+o,f=u.text.replace('"','"');f||(f=M.util.get_string("blank","qtype_ddimageortext"));var l='
'+''+f+" 
",c=e.Node.create(l);n[u.group].append(c),c.setStyles({opacity:.5}),c.setData("xy",u.xy),c.setData("place",o),c.setData("inputid",u.fieldname.replace(":","_")),c.setData("group",u.group);var h=new e.DD.Drop({node:c,groups:[u.group]});h.on("drop:hit",s,this)}}},{NAME:i,ATTRS:{}}),e.Event.define("dragchange",{_event:e.UA.webkit||e.UA.ie?"keydown":"keypress",_keys:{32:"next",37:"previous",38:"previous",39:"next",40:"next",27:"remove"},_keyHandler:function(e,t){this._keys[e.keyCode]&&(e.direction=this._keys[e.keyCode],t.fire(e))},on:function(e,t,n){t._detacher=e.on(this._event,this._keyHandler,this,n)}}),M.qtype_ddimageortext.init_question=function(e){return new s(e)}},"@VERSION@",{requires:["node","dd","dd-drop","dd-constrain"]}); diff --git a/question/type/ddimageortext/yui/build/moodle-qtype_ddimageortext-dd/moodle-qtype_ddimageortext-dd.js b/question/type/ddimageortext/yui/build/moodle-qtype_ddimageortext-dd/moodle-qtype_ddimageortext-dd.js deleted file mode 100644 index 022e28e35caf0..0000000000000 --- a/question/type/ddimageortext/yui/build/moodle-qtype_ddimageortext-dd/moodle-qtype_ddimageortext-dd.js +++ /dev/null @@ -1,546 +0,0 @@ -YUI.add('moodle-qtype_ddimageortext-dd', function (Y, NAME) { - -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -var DDIMAGEORTEXTDDNAME = 'ddimageortext_dd'; -var DDIMAGEORTEXT_DD = function() { - DDIMAGEORTEXT_DD.superclass.constructor.apply(this, arguments); -}; - -/** - * This is the base class for the question rendering and question editing form code. - */ -Y.extend(DDIMAGEORTEXT_DD, Y.Base, { - doc: null, - polltimer: null, - afterimageloaddone: false, - poll_for_image_load: function(e, waitforimageconstrain, pause, doafterwords) { - if (this.afterimageloaddone) { - return; - } - var bgdone = this.doc.bg_img().get('complete'); - if (waitforimageconstrain) { - bgdone = bgdone && this.doc.bg_img().hasClass('constrained'); - } - var alldragsloaded = !this.doc.drag_item_homes().some(function(dragitemhome) { - // in 'some' loop returning true breaks the loop and is passed as return value from - // 'some' else returns false. Can be though of as equivalent to ||. - if (dragitemhome.get('tagName') !== 'IMG') { - return false; - } - var done = (dragitemhome.get('complete')); - if (waitforimageconstrain) { - done = done && dragitemhome.hasClass('constrained'); - } - return !done; - }); - if (bgdone && alldragsloaded) { - if (this.polltimer !== null) { - this.polltimer.cancel(); - this.polltimer = null; - } - this.doc.drag_item_homes().detach('load', this.poll_for_image_load); - this.doc.bg_img().detach('load', this.poll_for_image_load); - if (pause !== 0) { - Y.later(pause, this, doafterwords); - } else { - doafterwords.call(this); - } - this.afterimageloaddone = true; - } else if (this.polltimer === null) { - var pollarguments = [null, waitforimageconstrain, pause, doafterwords]; - this.polltimer = - Y.later(1000, this, this.poll_for_image_load, pollarguments, true); - } - }, - /** - * Object to encapsulate operations on dd area. - */ - doc_structure: function(mainobj) { - var topnode = Y.one(this.get('topnode')); - var dragitemsarea = topnode.one('div.dragitems'); - var dropbgarea = topnode.one('div.droparea'); - return { - top_node: function() { - return topnode; - }, - drag_items: function() { - return dragitemsarea.all('.drag'); - }, - drop_zones: function() { - return topnode.all('div.dropzones div.dropzone'); - }, - drop_zone_group: function(groupno) { - return topnode.all('div.dropzones div.group' + groupno); - }, - drag_items_cloned_from: function(dragitemno) { - return dragitemsarea.all('.dragitems' + dragitemno); - }, - drag_item: function(draginstanceno) { - return dragitemsarea.one('.draginstance' + draginstanceno); - }, - drag_items_in_group: function(groupno) { - return dragitemsarea.all('.drag.group' + groupno); - }, - drag_item_homes: function() { - return dragitemsarea.all('.draghome'); - }, - bg_img: function() { - return topnode.one('.dropbackground'); - }, - load_bg_img: function(url) { - dropbgarea.setContent(''); - this.bg_img().on('load', this.on_image_load, this, 'bg_image'); - }, - add_or_update_drag_item_home: function(dragitemno, url, alt, group) { - var oldhome = this.drag_item_home(dragitemno); - var classes = 'draghome dragitemhomes' + dragitemno + ' group' + group; - var imghtml = '' + alt + ''; - var divhtml = '
' + alt + '
'; - if (oldhome === null) { - if (url) { - dragitemsarea.append(imghtml); - } else if (alt !== '') { - dragitemsarea.append(divhtml); - } - } else { - if (url) { - dragitemsarea.insert(imghtml, oldhome); - } else if (alt !== '') { - dragitemsarea.insert(divhtml, oldhome); - } - oldhome.remove(true); - } - var newlycreated = dragitemsarea.one('.dragitemhomes' + dragitemno); - if (newlycreated !== null) { - newlycreated.setData('groupno', group); - newlycreated.setData('dragitemno', dragitemno); - } - }, - drag_item_home: function(dragitemno) { - return dragitemsarea.one('.dragitemhomes' + dragitemno); - }, - get_classname_numeric_suffix: function(node, prefix) { - var classes = node.getAttribute('class'); - if (classes !== '') { - var classesarr = classes.split(' '); - for (var index = 0; index < classesarr.length; index++) { - var patt1 = new RegExp('^' + prefix + '([0-9])+$'); - if (patt1.test(classesarr[index])) { - var patt2 = new RegExp('([0-9])+$'); - var match = patt2.exec(classesarr[index]); - return +match[0]; - } - } - } - throw 'Prefix "' + prefix + '" not found in class names.'; - }, - clone_new_drag_item: function(draginstanceno, dragitemno) { - var draghome = this.drag_item_home(dragitemno); - if (draghome === null) { - return null; - } - var drag = draghome.cloneNode(true); - drag.removeClass('dragitemhomes' + dragitemno); - drag.addClass('dragitems' + dragitemno); - drag.addClass('draginstance' + draginstanceno); - drag.removeClass('draghome'); - drag.addClass('drag'); - drag.setStyles({'visibility': 'visible', 'position': 'absolute'}); - drag.setData('draginstanceno', draginstanceno); - drag.setData('dragitemno', dragitemno); - draghome.get('parentNode').appendChild(drag); - return drag; - }, - draggable_for_question: function(drag, group, choice) { - new Y.DD.Drag({ - node: drag, - dragMode: 'point', - groups: [group] - }).plug(Y.Plugin.DDConstrained, {constrain2node: topnode}); - - drag.setData('group', group); - drag.setData('choice', choice); - }, - draggable_for_form: function(drag) { - var dd = new Y.DD.Drag({ - node: drag, - dragMode: 'point' - }).plug(Y.Plugin.DDConstrained, {constrain2node: topnode}); - dd.on('drag:end', function(e) { - var dragnode = e.target.get('node'); - var draginstanceno = dragnode.getData('draginstanceno'); - var gooddrop = dragnode.getData('gooddrop'); - - if (!gooddrop) { - mainobj.reset_drag_xy(draginstanceno); - } else { - mainobj.set_drag_xy(draginstanceno, [e.pageX, e.pageY]); - } - }, this); - dd.on('drag:start', function(e) { - var drag = e.target; - drag.get('node').setData('gooddrop', false); - }, this); - - } - - }; - }, - - update_padding_sizes_all: function() { - for (var groupno = 1; groupno <= 8; groupno++) { - this.update_padding_size_for_group(groupno); - } - }, - update_padding_size_for_group: function(groupno) { - var groupitems = this.doc.top_node().all('.draghome.group' + groupno); - if (groupitems.size() !== 0) { - var maxwidth = 0; - var maxheight = 0; - groupitems.each(function(item) { - maxwidth = Math.max(maxwidth, item.get('clientWidth')); - maxheight = Math.max(maxheight, item.get('clientHeight')); - }, this); - groupitems.each(function(item) { - var margintopbottom = Math.round((10 + maxheight - item.get('clientHeight')) / 2); - var marginleftright = Math.round((10 + maxwidth - item.get('clientWidth')) / 2); - item.setStyle('padding', margintopbottom + 'px ' + marginleftright + 'px ' + - margintopbottom + 'px ' + marginleftright + 'px'); - }, this); - this.doc.drop_zone_group(groupno).setStyles({'width': maxwidth + 10, - 'height': maxheight + 10}); - } - }, - convert_to_window_xy: function(bgimgxy) { - return [Number(bgimgxy[0]) + this.doc.bg_img().getX() + 1, - Number(bgimgxy[1]) + this.doc.bg_img().getY() + 1]; - } -}, { - NAME: DDIMAGEORTEXTDDNAME, - ATTRS: { - drops: {value: null}, - readonly: {value: false}, - topnode: {value: null} - } -}); - -M.qtype_ddimageortext = M.qtype_ddimageortext || {}; -M.qtype_ddimageortext.dd_base_class = DDIMAGEORTEXT_DD; - -var DDIMAGEORTEXTQUESTIONNAME = 'ddimageortext_question'; -var DDIMAGEORTEXT_QUESTION = function() { - DDIMAGEORTEXT_QUESTION.superclass.constructor.apply(this, arguments); -}; -/** - * This is the code for question rendering. - */ -Y.extend(DDIMAGEORTEXT_QUESTION, M.qtype_ddimageortext.dd_base_class, { - passiveSupported: false, - pendingid: '', - initializer: function() { - this.pendingid = 'qtype_ddimageortext-' + Math.random().toString(36).slice(2); // Random string. - M.util.js_pending(this.pendingid); - this.doc = this.doc_structure(this); - this.poll_for_image_load(null, false, 10, this.create_all_drag_and_drops); - this.doc.bg_img().after('load', this.poll_for_image_load, this, - false, 10, this.create_all_drag_and_drops); - this.doc.drag_item_homes().after('load', this.poll_for_image_load, this, - false, 10, this.create_all_drag_and_drops); - if (!this.get('readonly')) { - Y.later(500, this, this.reposition_drags_for_question, true); - } else { - Y.one('window').on('resize', function() { - this.reposition_drags_for_question(); - }, this); - } - this.checkPassiveSupported(); - }, - - /** - * prevent_touchmove_from_scrolling allows users of touch screen devices to - * use drag and drop and normal scrolling at the same time. I.e. when - * touching and dragging a draggable item, the screen does not scroll, but - * you can scroll by touching other area of the screen apart from the - * draggable items. - */ - prevent_touchmove_from_scrolling: function(drag) { - var touchmove = (Y.UA.ie) ? 'MSPointerMove' : 'touchmove'; - var eventHandler = function(event) { - event.preventDefault(); - }; - var dragId = drag.get('id'); - var el = document.getElementById(dragId); - // Note do not dynamically add events within another event, as this causes issues on iOS11.3. - // See https://github.com/atlassian/react-beautiful-dnd/issues/413 and - // https://bugs.webkit.org/show_bug.cgi?id=184250 for fuller explanation. - el.addEventListener(touchmove, eventHandler, this.passiveSupported ? {passive: false, capture: true} : false); - }, - - /** - * Some older browsers do not support passing an options object to addEventListener. - * This is a check from https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener. - */ - checkPassiveSupported: function() { - try { - var options = Object.defineProperty({}, 'passive', { - get: function() { - this.passiveSupported = true; - }.bind(this) - }); - window.addEventListener('test', options, options); - window.removeEventListener('test', options, options); - } catch (err) { - this.passiveSupported = false; - } - }, - - create_all_drag_and_drops: function() { - this.init_drops(); - this.update_padding_sizes_all(); - var i = 0; - this.doc.drag_item_homes().each(function(dragitemhome) { - var dragitemno = Number(this.doc.get_classname_numeric_suffix(dragitemhome, 'dragitemhomes')); - var choice = +this.doc.get_classname_numeric_suffix(dragitemhome, 'choice'); - var group = +this.doc.get_classname_numeric_suffix(dragitemhome, 'group'); - var groupsize = this.doc.drop_zone_group(group).size(); - var dragnode = this.doc.clone_new_drag_item(i, dragitemno); - i++; - if (!this.get('readonly')) { - this.doc.draggable_for_question(dragnode, group, choice); - - // Prevent scrolling whilst dragging on Adroid devices. - this.prevent_touchmove_from_scrolling(dragnode); - } - if (dragnode.hasClass('infinite')) { - var dragstocreate = groupsize - 1; - while (dragstocreate > 0) { - dragnode = this.doc.clone_new_drag_item(i, dragitemno); - i++; - if (!this.get('readonly')) { - this.doc.draggable_for_question(dragnode, group, choice); - - // Prevent scrolling whilst dragging on Adroid devices. - this.prevent_touchmove_from_scrolling(dragnode); - } - dragstocreate--; - } - } - }, this); - this.reposition_drags_for_question(); - if (!this.get('readonly')) { - this.doc.drop_zones().set('tabIndex', 0); - this.doc.drop_zones().each( - function(v) { - v.on('dragchange', this.drop_zone_key_press, this); - }, this); - } - M.util.js_complete(this.pendingid); - }, - drop_zone_key_press: function(e) { - switch (e.direction) { - case 'next' : - this.place_next_drag_in(e.target); - break; - case 'previous' : - this.place_previous_drag_in(e.target); - break; - case 'remove' : - this.remove_drag_from_drop(e.target); - break; - } - e.preventDefault(); - this.reposition_drags_for_question(); - }, - place_next_drag_in: function(drop) { - this.search_for_unplaced_drop_choice(drop, 1); - }, - place_previous_drag_in: function(drop) { - this.search_for_unplaced_drop_choice(drop, -1); - }, - search_for_unplaced_drop_choice: function(drop, direction) { - var next; - var current = this.current_drag_in_drop(drop); - if ('' === current) { - if (direction === 1) { - next = 1; - } else { - next = 1; - var groupno = drop.getData('group'); - this.doc.drag_items_in_group(groupno).each(function(drag) { - next = Math.max(next, drag.getData('choice')); - }, this); - } - } else { - next = +current + direction; - } - var drag; - do { - if (this.get_choices_for_drop(next, drop).size() === 0) { - this.remove_drag_from_drop(drop); - return; - } else { - drag = this.get_unplaced_choice_for_drop(next, drop); - } - next = next + direction; - } while (drag === null); - this.place_drag_in_drop(drag, drop); - }, - current_drag_in_drop: function(drop) { - var inputid = drop.getData('inputid'); - var inputnode = Y.one('input#' + inputid); - return inputnode.get('value'); - }, - remove_drag_from_drop: function(drop) { - this.place_drag_in_drop(null, drop); - }, - place_drag_in_drop: function(drag, drop) { - var inputid = drop.getData('inputid'); - var inputnode = Y.one('input#' + inputid); - if (drag !== null) { - inputnode.set('value', drag.getData('choice')); - } else { - inputnode.set('value', ''); - } - }, - reposition_drags_for_question: function(dotimeout) { - this.doc.drag_items().removeClass('placed'); - this.doc.drag_items().each(function(dragitem) { - if (dragitem.dd !== undefined) { - dragitem.dd.detachAll('drag:start'); - } - }, this); - this.doc.drop_zones().each(function(dropzone) { - var relativexy = dropzone.getData('xy'); - dropzone.setXY(this.convert_to_window_xy(relativexy)); - var inputcss = 'input#' + dropzone.getData('inputid'); - var input = this.doc.top_node().one(inputcss); - var choice = input.get('value'); - if (choice !== "") { - var dragitem = this.get_unplaced_choice_for_drop(choice, dropzone); - if (dragitem !== null) { - dragitem.setXY(dropzone.getXY()); - dragitem.addClass('placed'); - if (dragitem.dd !== undefined) { - dragitem.dd.once('drag:start', function(e, input) { - input.set('value', ''); - e.target.get('node').removeClass('placed'); - }, this, input); - } - } - } - }, this); - this.doc.drag_items().each(function(dragitem) { - if (!dragitem.hasClass('placed') && !dragitem.hasClass('yui3-dd-dragging')) { - var dragitemhome = this.doc.drag_item_home(dragitem.getData('dragitemno')); - dragitem.setXY(dragitemhome.getXY()); - } - }, this); - if (dotimeout) { - Y.later(500, this, this.reposition_drags_for_question, true); - } - }, - get_choices_for_drop: function(choice, drop) { - var group = drop.getData('group'); - return this.doc.top_node().all( - 'div.dragitemgroup' + group + ' .choice' + choice + '.drag'); - }, - get_unplaced_choice_for_drop: function(choice, drop) { - var dragitems = this.get_choices_for_drop(choice, drop); - var dragitem = null; - dragitems.some(function(d) { - if (this.get('readonly') || (!d.hasClass('placed') && !d.hasClass('yui3-dd-dragging'))) { - dragitem = d; - return true; - } else { - return false; - } - }); - return dragitem; - }, - init_drops: function() { - var dropareas = this.doc.top_node().one('div.dropzones'); - var groupnodes = {}; - for (var groupno = 1; groupno <= 8; groupno++) { - var groupnode = Y.Node.create('
'); - dropareas.append(groupnode); - groupnodes[groupno] = groupnode; - } - var drop_hit_handler = function(e) { - var drag = e.drag.get('node'); - var drop = e.drop.get('node'); - if (Number(drop.getData('group')) === drag.getData('group')) { - this.place_drag_in_drop(drag, drop); - } - }; - for (var dropno in this.get('drops')) { - var drop = this.get('drops')[dropno]; - var nodeclass = 'dropzone group' + drop.group + ' place' + dropno; - var title = drop.text.replace('"', '\"'); - if (!title) { - title = M.util.get_string('blank', 'qtype_ddimageortext'); - } - var dropnodehtml = '
' + - '' + title + ' 
'; - var dropnode = Y.Node.create(dropnodehtml); - groupnodes[drop.group].append(dropnode); - dropnode.setStyles({'opacity': 0.5}); - dropnode.setData('xy', drop.xy); - dropnode.setData('place', dropno); - dropnode.setData('inputid', drop.fieldname.replace(':', '_')); - dropnode.setData('group', drop.group); - var dropdd = new Y.DD.Drop({ - node: dropnode, groups: [drop.group]}); - dropdd.on('drop:hit', drop_hit_handler, this); - } - } -}, {NAME: DDIMAGEORTEXTQUESTIONNAME, ATTRS: {}}); - -Y.Event.define('dragchange', { - // Webkit and IE repeat keydown when you hold down arrow keys. - // Opera links keypress to page scroll; others keydown. - // Firefox prevents page scroll via preventDefault() on either - // keydown or keypress. - _event: (Y.UA.webkit || Y.UA.ie) ? 'keydown' : 'keypress', - - _keys: { - '32': 'next', // Space - '37': 'previous', // Left arrow - '38': 'previous', // Up arrow - '39': 'next', // Right arrow - '40': 'next', // Down arrow - '27': 'remove' // Escape - }, - - _keyHandler: function(e, notifier) { - if (this._keys[e.keyCode]) { - e.direction = this._keys[e.keyCode]; - notifier.fire(e); - } - }, - - on: function(node, sub, notifier) { - sub._detacher = node.on(this._event, this._keyHandler, - this, notifier); - } -}); - -M.qtype_ddimageortext.init_question = function(config) { - return new DDIMAGEORTEXT_QUESTION(config); -}; - - -}, '@VERSION@', {"requires": ["node", "dd", "dd-drop", "dd-constrain"]}); diff --git a/question/type/ddimageortext/yui/build/moodle-qtype_ddimageortext-form/moodle-qtype_ddimageortext-form-debug.js b/question/type/ddimageortext/yui/build/moodle-qtype_ddimageortext-form/moodle-qtype_ddimageortext-form-debug.js deleted file mode 100644 index 6136669ce8e78..0000000000000 --- a/question/type/ddimageortext/yui/build/moodle-qtype_ddimageortext-form/moodle-qtype_ddimageortext-form-debug.js +++ /dev/null @@ -1,369 +0,0 @@ -YUI.add('moodle-qtype_ddimageortext-form', function (Y, NAME) { - -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/** - * This is the question editing form code. - */ -var DDIMAGEORTEXTFORMNAME = 'moodle-qtype_ddimageortext-form'; -var DDIMAGEORTEXT_FORM = function() { - DDIMAGEORTEXT_FORM.superclass.constructor.apply(this, arguments); -}; - -Y.extend(DDIMAGEORTEXT_FORM, M.qtype_ddimageortext.dd_base_class, { - pendingid: '', - fp: null, - - initializer: function() { - this.pendingid = 'qtype_ddimageortext-form-' + Math.random().toString(36).slice(2); // Random string. - M.util.js_pending(this.pendingid); - this.fp = this.file_pickers(); - var tn = Y.one(this.get('topnode')); - tn.one('div.fcontainer').append('
' + - '
'); - this.doc = this.doc_structure(this); - this.draw_dd_area(); - }, - - draw_dd_area: function() { - var bgimageurl = this.fp.file('bgimage').href; - this.stop_selector_events(); - this.set_options_for_drag_item_selectors(); - if (bgimageurl !== null) { - this.doc.load_bg_img(bgimageurl); - this.load_drag_homes(); - - var drop = new Y.DD.Drop({ - node: this.doc.bg_img() - }); - // Listen for a drop:hit on the background image - drop.on('drop:hit', function(e) { - e.drag.get('node').setData('gooddrop', true); - }); - - this.afterimageloaddone = false; - this.doc.bg_img().on('load', this.constrain_image_size, this, 'bgimage'); - this.doc.drag_item_homes() - .on('load', this.constrain_image_size, this, 'dragimage'); - this.doc.bg_img().after('load', this.poll_for_image_load, this, - true, 0, this.after_all_images_loaded); - this.doc.drag_item_homes().after('load', this.poll_for_image_load, this, - true, 0, this.after_all_images_loaded); - } else { - this.setup_form_events(); - M.util.js_complete(this.pendingid); - } - this.update_visibility_of_file_pickers(); - }, - - after_all_images_loaded: function() { - this.update_padding_sizes_all(); - this.update_drag_instances(); - this.reposition_drags_for_form(); - this.set_options_for_drag_item_selectors(); - this.setup_form_events(); - Y.later(500, this, this.reposition_drags_for_form, [], true); - }, - - constrain_image_size: function(e, imagetype) { - var maxsize = this.get('maxsizes')[imagetype]; - var reduceby = Math.max(e.target.get('width') / maxsize.width, - e.target.get('height') / maxsize.height); - if (reduceby > 1) { - e.target.set('width', Math.floor(e.target.get('width') / reduceby)); - } - e.target.addClass('constrained'); - e.target.detach('load', this.constrain_image_size); - }, - - load_drag_homes: function() { - // Set up drag items homes. - for (var i = 0; i < this.form.get_form_value('noitems', []); i++) { - this.load_drag_home(i); - } - }, - - load_drag_home: function(dragitemno) { - var url = null; - if ('image' === this.form.get_form_value('drags', [dragitemno, 'dragitemtype'])) { - url = this.fp.file(this.form.to_name_with_index('dragitem', [dragitemno])).href; - } - this.doc.add_or_update_drag_item_home(dragitemno, url, - this.form.get_form_value('draglabel', [dragitemno]), - this.form.get_form_value('drags', [dragitemno, 'draggroup'])); - }, - - update_drag_instances: function() { - // Set up drop zones. - for (var i = 0; i < this.form.get_form_value('nodropzone', []); i++) { - var dragitemno = this.form.get_form_value('drops', [i, 'choice']); - if (dragitemno !== '0' && (this.doc.drag_item(i) === null)) { - var drag = this.doc.clone_new_drag_item(i, dragitemno - 1); - if (drag !== null) { - this.doc.draggable_for_form(drag); - } - } - } - }, - set_options_for_drag_item_selectors: function() { - var dragitemsoptions = {'0': ''}; - for (var i = 0; i < this.form.get_form_value('noitems', []); i++) { - var label = this.form.get_form_value('draglabel', [i]); - var file = this.fp.file(this.form.to_name_with_index('dragitem', [i])); - if ('image' === this.form.get_form_value('drags', [i, 'dragitemtype']) - && file.name !== null) { - dragitemsoptions[i + 1] = (i + 1) + '. ' + label + ' (' + file.name + ')'; - } else if (label !== '') { - dragitemsoptions[i + 1] = (i + 1) + '. ' + label; - } - } - for (i = 0; i < this.form.get_form_value('nodropzone', []); i++) { - var selector = Y.one('#id_drops_' + i + '_choice'); - var selectedvalue = selector.get('value'); - selector.all('option').remove(true); - for (var value in dragitemsoptions) { - value = +value; - var option = ''; - selector.append(option); - var optionnode = selector.one('option[value="' + value + '"]'); - if (value === +selectedvalue) { - optionnode.set('selected', true); - } else { - if (value !== 0) { // No item option is always selectable. - var cbel = Y.one('#id_drags_' + (value - 1) + '_infinite'); - if (cbel && !cbel.get('checked')) { - if (this.item_is_allocated_to_dropzone(value)) { - optionnode.set('disabled', true); - } - } - } - } - } - } - }, - - stop_selector_events: function() { - Y.all('fieldset#id_dropzoneheader select').detachAll(); - }, - - /** - * Checks if the specified drag item is allocated to a dropzone. - * - * @method item_is_allocated_to_dropzone - * @param {Number} value of the drag item to check - * @return {Boolean} true if item is allocated to dropzone - */ - item_is_allocated_to_dropzone: function(itemvalue) { - return Y.all('fieldset#id_dropzoneheader select').some(function(selectNode) { - return Number(selectNode.get('value')) === itemvalue; - }); - }, - - setup_form_events: function() { - // Events triggered by changes to form data. - - // X and y coordinates. - Y.all('fieldset#id_dropzoneheader input').on('blur', function(e) { - var name = e.target.getAttribute('name'); - var draginstanceno = this.form.from_name_with_index(name).indexes[0]; - var fromform = [this.form.get_form_value('drops', [draginstanceno, 'xleft']), - this.form.get_form_value('drops', [draginstanceno, 'ytop'])]; - var constrainedxy = this.constrain_xy(draginstanceno, fromform); - this.form.set_form_value('drops', [draginstanceno, 'xleft'], constrainedxy[0]); - this.form.set_form_value('drops', [draginstanceno, 'ytop'], constrainedxy[1]); - }, this); - - // Change in selected item. - Y.all('fieldset#id_dropzoneheader select').on('change', function(e) { - var name = e.target.getAttribute('name'); - var draginstanceno = this.form.from_name_with_index(name).indexes[0]; - var old = this.doc.drag_item(draginstanceno); - if (old !== null) { - old.remove(true); - } - this.draw_dd_area(); - }, this); - - for (var i = 0; i < this.form.get_form_value('noitems', []); i++) { - // Change to group selector. - Y.all('#fgroup_id_drags_' + i + ' select.draggroup').on('change', this.redraw_dd_area, this); - Y.all('#fgroup_id_drags_' + i + ' select.dragitemtype').on('change', this.redraw_dd_area, this); - Y.all('fieldset#draggableitemheader_' + i + ' input[type="text"]') - .on('blur', this.set_options_for_drag_item_selectors, this); - // Change to infinite checkbox. - Y.all('fieldset#draggableitemheader_' + i + ' input[type="checkbox"]') - .on('change', this.set_options_for_drag_item_selectors, this); - } - // Event on file picker new file selection. - Y.after(function(e) { - var name = this.fp.name(e.id); - if (name !== 'bgimage') { - this.doc.drag_items().remove(true); - } - this.draw_dd_area(); - }, M.form_filepicker, 'callback', this); - }, - - /** - * Redraws drag and drop preview area. - * - * @method redraw_dd_area - */ - redraw_dd_area: function() { - this.doc.drag_items().remove(true); - this.draw_dd_area(); - }, - - update_visibility_of_file_pickers: function() { - for (var i = 0; i < this.form.get_form_value('noitems', []); i++) { - if ('image' === this.form.get_form_value('drags', [i, 'dragitemtype'])) { - Y.one('input#id_dragitem_' + i).get('parentNode').get('parentNode') - .setStyle('display', 'block'); - } else { - Y.one('input#id_dragitem_' + i).get('parentNode').get('parentNode') - .setStyle('display', 'none'); - } - } - }, - - reposition_drags_for_form: function() { - this.doc.drag_items().each(function(drag) { - var draginstanceno = drag.getData('draginstanceno'); - this.reposition_drag_for_form(draginstanceno); - }, this); - M.util.js_complete(this.pendingid); - }, - - reposition_drag_for_form: function(draginstanceno) { - var drag = this.doc.drag_item(draginstanceno); - if (null !== drag && !drag.hasClass('yui3-dd-dragging')) { - var fromform = [this.form.get_form_value('drops', [draginstanceno, 'xleft']), - this.form.get_form_value('drops', [draginstanceno, 'ytop'])]; - if (fromform[0] === '' && fromform[1] === '') { - var dragitemno = drag.getData('dragitemno'); - drag.setXY(this.doc.drag_item_home(dragitemno).getXY()); - } else { - drag.setXY(this.convert_to_window_xy(fromform)); - } - } - }, - set_drag_xy: function(draginstanceno, xy) { - xy = this.constrain_xy(draginstanceno, this.convert_to_bg_img_xy(xy)); - this.form.set_form_value('drops', [draginstanceno, 'xleft'], Math.round(xy[0])); - this.form.set_form_value('drops', [draginstanceno, 'ytop'], Math.round(xy[1])); - }, - reset_drag_xy: function(draginstanceno) { - this.form.set_form_value('drops', [draginstanceno, 'xleft'], ''); - this.form.set_form_value('drops', [draginstanceno, 'ytop'], ''); - }, - - // make sure xy value is not out of bounds of bg image - constrain_xy: function(draginstanceno, bgimgxy) { - var drag = this.doc.drag_item(draginstanceno); - var xleftconstrained = - Math.min(bgimgxy[0], this.doc.bg_img().get('width') - drag.get('offsetWidth')); - var ytopconstrained = - Math.min(bgimgxy[1], this.doc.bg_img().get('height') - drag.get('offsetHeight')); - xleftconstrained = Math.max(xleftconstrained, 0); - ytopconstrained = Math.max(ytopconstrained, 0); - return [xleftconstrained, ytopconstrained]; - }, - convert_to_bg_img_xy: function(windowxy) { - return [Number(windowxy[0]) - this.doc.bg_img().getX() - 1, - Number(windowxy[1]) - this.doc.bg_img().getY() - 1]; - }, - - /** - * Low level operations on form. - */ - form: { - to_name_with_index: function(name, indexes) { - var indexstring = name; - for (var i = 0; i < indexes.length; i++) { - indexstring = indexstring + '[' + indexes[i] + ']'; - } - return indexstring; - }, - get_el: function(name, indexes) { - var form = document.getElementById('mform1'); - return form.elements[this.to_name_with_index(name, indexes)]; - }, - get_form_value: function(name, indexes) { - var el = this.get_el(name, indexes); - if (el.type === 'checkbox') { - return el.checked; - } else { - return el.value; - } - }, - set_form_value: function(name, indexes, value) { - var el = this.get_el(name, indexes); - if (el.type === 'checkbox') { - el.checked = value; - } else { - el.value = value; - } - }, - from_name_with_index: function(name) { - var toreturn = {}; - toreturn.indexes = []; - var bracket = name.indexOf('['); - toreturn.name = name.substring(0, bracket); - while (bracket !== -1) { - var end = name.indexOf(']', bracket + 1); - toreturn.indexes.push(name.substring(bracket + 1, end)); - bracket = name.indexOf('[', end + 1); - } - return toreturn; - } - }, - - file_pickers: function() { - var draftitemidstoname; - var nametoparentnode; - if (draftitemidstoname === undefined) { - draftitemidstoname = {}; - nametoparentnode = {}; - var filepickers = Y.all('form.mform input.filepickerhidden'); - filepickers.each(function(filepicker) { - draftitemidstoname[filepicker.get('value')] = filepicker.get('name'); - nametoparentnode[filepicker.get('name')] = filepicker.get('parentNode'); - }, this); - } - var toreturn = { - file: function(name) { - var parentnode = nametoparentnode[name]; - var fileanchor = parentnode.one('div.filepicker-filelist a'); - if (fileanchor) { - return {href: fileanchor.get('href'), name: fileanchor.get('innerHTML')}; - } else { - return {href: null, name: null}; - } - }, - name: function(draftitemid) { - return draftitemidstoname[draftitemid]; - } - }; - return toreturn; - } -}, {NAME: DDIMAGEORTEXTFORMNAME, ATTRS: {maxsizes: {value: null}}}); -M.qtype_ddimageortext = M.qtype_ddimageortext || {}; -M.qtype_ddimageortext.init_form = function(config) { - return new DDIMAGEORTEXT_FORM(config); -}; - - -}, '@VERSION@', {"requires": ["moodle-qtype_ddimageortext-dd", "form_filepicker"]}); diff --git a/question/type/ddimageortext/yui/build/moodle-qtype_ddimageortext-form/moodle-qtype_ddimageortext-form-min.js b/question/type/ddimageortext/yui/build/moodle-qtype_ddimageortext-form/moodle-qtype_ddimageortext-form-min.js deleted file mode 100644 index eed668e9557a4..0000000000000 --- a/question/type/ddimageortext/yui/build/moodle-qtype_ddimageortext-form/moodle-qtype_ddimageortext-form-min.js +++ /dev/null @@ -1,2 +0,0 @@ -YUI.add("moodle-qtype_ddimageortext-form",function(e,t){var n="moodle-qtype_ddimageortext-form",r=function(){r.superclass.constructor.apply(this,arguments)};e.extend(r,M.qtype_ddimageortext.dd_base_class,{pendingid:"",fp:null,initializer:function(){this.pendingid="qtype_ddimageortext-form-"+Math.random().toString(36).slice(2),M.util.js_pending(this.pendingid),this.fp=this.file_pickers();var t=e.one(this.get("topnode"));t.one("div.fcontainer").append('
'),this.doc=this.doc_structure(this),this.draw_dd_area()},draw_dd_area:function(){var t=this.fp.file("bgimage").href;this.stop_selector_events(),this.set_options_for_drag_item_selectors();if(t!==null){this.doc.load_bg_img(t),this.load_drag_homes();var n=new e.DD.Drop({node:this.doc.bg_img()});n.on("drop:hit",function(e){e.drag.get("node").setData("gooddrop",!0)}),this.afterimageloaddone=!1,this.doc.bg_img().on("load",this.constrain_image_size,this,"bgimage"),this.doc.drag_item_homes().on("load",this.constrain_image_size,this,"dragimage"),this.doc.bg_img().after("load",this.poll_for_image_load,this,!0,0,this.after_all_images_loaded),this.doc.drag_item_homes().after("load",this.poll_for_image_load,this,!0,0,this.after_all_images_loaded)}else this.setup_form_events(),M.util.js_complete(this.pendingid);this.update_visibility_of_file_pickers()},after_all_images_loaded:function(){this.update_padding_sizes_all(),this.update_drag_instances(),this.reposition_drags_for_form(),this.set_options_for_drag_item_selectors(),this.setup_form_events(),e.later(500,this,this.reposition_drags_for_form,[],!0)},constrain_image_size:function(e,t){var n=this.get("maxsizes")[t],r=Math.max(e.target.get("width")/n.width,e.target.get("height")/n.height);r>1&&e.target.set("width",Math.floor(e.target.get("width")/r)),e.target.addClass("constrained"),e.target.detach("load",this.constrain_image_size)},load_drag_homes:function(){for(var e=0;e'+t[u]+"";s.append(a);var f=s.one('option[value="'+u+'"]');if(u===+o)f.set("selected",!0);else if(u!==0){var l=e.one("#id_drags_"+(u-1)+"_infinite");l&&!l.get("checked")&&this.item_is_allocated_to_dropzone(u)&&f.set("disabled",!0)}}}},stop_selector_events:function(){e.all("fieldset#id_dropzoneheader select").detachAll()},item_is_allocated_to_dropzone:function(t){return e.all("fieldset#id_dropzoneheader select").some(function(e){return Number(e.get("value"))===t})},setup_form_events:function(){e.all("fieldset#id_dropzoneheader input").on("blur",function(e){var t=e.target.getAttribute("name"),n=this.form.from_name_with_index(t).indexes[0],r=[this.form.get_form_value("drops",[n,"xleft"]),this.form.get_form_value("drops",[n,"ytop"])],i=this.constrain_xy(n,r);this.form.set_form_value("drops",[n,"xleft"],i[0]),this.form.set_form_value("drops",[n,"ytop"],i[1])},this),e.all("fieldset#id_dropzoneheader select").on("change",function(e){var t=e.target.getAttribute("name"),n=this.form.from_name_with_index(t).indexes[0],r=this.doc.drag_item(n);r!==null&&r.remove(!0),this.draw_dd_area()},this);for(var t=0;t. - -/** - * This is the question editing form code. - */ -var DDIMAGEORTEXTFORMNAME = 'moodle-qtype_ddimageortext-form'; -var DDIMAGEORTEXT_FORM = function() { - DDIMAGEORTEXT_FORM.superclass.constructor.apply(this, arguments); -}; - -Y.extend(DDIMAGEORTEXT_FORM, M.qtype_ddimageortext.dd_base_class, { - pendingid: '', - fp: null, - - initializer: function() { - this.pendingid = 'qtype_ddimageortext-form-' + Math.random().toString(36).slice(2); // Random string. - M.util.js_pending(this.pendingid); - this.fp = this.file_pickers(); - var tn = Y.one(this.get('topnode')); - tn.one('div.fcontainer').append('
' + - '
'); - this.doc = this.doc_structure(this); - this.draw_dd_area(); - }, - - draw_dd_area: function() { - var bgimageurl = this.fp.file('bgimage').href; - this.stop_selector_events(); - this.set_options_for_drag_item_selectors(); - if (bgimageurl !== null) { - this.doc.load_bg_img(bgimageurl); - this.load_drag_homes(); - - var drop = new Y.DD.Drop({ - node: this.doc.bg_img() - }); - // Listen for a drop:hit on the background image - drop.on('drop:hit', function(e) { - e.drag.get('node').setData('gooddrop', true); - }); - - this.afterimageloaddone = false; - this.doc.bg_img().on('load', this.constrain_image_size, this, 'bgimage'); - this.doc.drag_item_homes() - .on('load', this.constrain_image_size, this, 'dragimage'); - this.doc.bg_img().after('load', this.poll_for_image_load, this, - true, 0, this.after_all_images_loaded); - this.doc.drag_item_homes().after('load', this.poll_for_image_load, this, - true, 0, this.after_all_images_loaded); - } else { - this.setup_form_events(); - M.util.js_complete(this.pendingid); - } - this.update_visibility_of_file_pickers(); - }, - - after_all_images_loaded: function() { - this.update_padding_sizes_all(); - this.update_drag_instances(); - this.reposition_drags_for_form(); - this.set_options_for_drag_item_selectors(); - this.setup_form_events(); - Y.later(500, this, this.reposition_drags_for_form, [], true); - }, - - constrain_image_size: function(e, imagetype) { - var maxsize = this.get('maxsizes')[imagetype]; - var reduceby = Math.max(e.target.get('width') / maxsize.width, - e.target.get('height') / maxsize.height); - if (reduceby > 1) { - e.target.set('width', Math.floor(e.target.get('width') / reduceby)); - } - e.target.addClass('constrained'); - e.target.detach('load', this.constrain_image_size); - }, - - load_drag_homes: function() { - // Set up drag items homes. - for (var i = 0; i < this.form.get_form_value('noitems', []); i++) { - this.load_drag_home(i); - } - }, - - load_drag_home: function(dragitemno) { - var url = null; - if ('image' === this.form.get_form_value('drags', [dragitemno, 'dragitemtype'])) { - url = this.fp.file(this.form.to_name_with_index('dragitem', [dragitemno])).href; - } - this.doc.add_or_update_drag_item_home(dragitemno, url, - this.form.get_form_value('draglabel', [dragitemno]), - this.form.get_form_value('drags', [dragitemno, 'draggroup'])); - }, - - update_drag_instances: function() { - // Set up drop zones. - for (var i = 0; i < this.form.get_form_value('nodropzone', []); i++) { - var dragitemno = this.form.get_form_value('drops', [i, 'choice']); - if (dragitemno !== '0' && (this.doc.drag_item(i) === null)) { - var drag = this.doc.clone_new_drag_item(i, dragitemno - 1); - if (drag !== null) { - this.doc.draggable_for_form(drag); - } - } - } - }, - set_options_for_drag_item_selectors: function() { - var dragitemsoptions = {'0': ''}; - for (var i = 0; i < this.form.get_form_value('noitems', []); i++) { - var label = this.form.get_form_value('draglabel', [i]); - var file = this.fp.file(this.form.to_name_with_index('dragitem', [i])); - if ('image' === this.form.get_form_value('drags', [i, 'dragitemtype']) - && file.name !== null) { - dragitemsoptions[i + 1] = (i + 1) + '. ' + label + ' (' + file.name + ')'; - } else if (label !== '') { - dragitemsoptions[i + 1] = (i + 1) + '. ' + label; - } - } - for (i = 0; i < this.form.get_form_value('nodropzone', []); i++) { - var selector = Y.one('#id_drops_' + i + '_choice'); - var selectedvalue = selector.get('value'); - selector.all('option').remove(true); - for (var value in dragitemsoptions) { - value = +value; - var option = ''; - selector.append(option); - var optionnode = selector.one('option[value="' + value + '"]'); - if (value === +selectedvalue) { - optionnode.set('selected', true); - } else { - if (value !== 0) { // No item option is always selectable. - var cbel = Y.one('#id_drags_' + (value - 1) + '_infinite'); - if (cbel && !cbel.get('checked')) { - if (this.item_is_allocated_to_dropzone(value)) { - optionnode.set('disabled', true); - } - } - } - } - } - } - }, - - stop_selector_events: function() { - Y.all('fieldset#id_dropzoneheader select').detachAll(); - }, - - /** - * Checks if the specified drag item is allocated to a dropzone. - * - * @method item_is_allocated_to_dropzone - * @param {Number} value of the drag item to check - * @return {Boolean} true if item is allocated to dropzone - */ - item_is_allocated_to_dropzone: function(itemvalue) { - return Y.all('fieldset#id_dropzoneheader select').some(function(selectNode) { - return Number(selectNode.get('value')) === itemvalue; - }); - }, - - setup_form_events: function() { - // Events triggered by changes to form data. - - // X and y coordinates. - Y.all('fieldset#id_dropzoneheader input').on('blur', function(e) { - var name = e.target.getAttribute('name'); - var draginstanceno = this.form.from_name_with_index(name).indexes[0]; - var fromform = [this.form.get_form_value('drops', [draginstanceno, 'xleft']), - this.form.get_form_value('drops', [draginstanceno, 'ytop'])]; - var constrainedxy = this.constrain_xy(draginstanceno, fromform); - this.form.set_form_value('drops', [draginstanceno, 'xleft'], constrainedxy[0]); - this.form.set_form_value('drops', [draginstanceno, 'ytop'], constrainedxy[1]); - }, this); - - // Change in selected item. - Y.all('fieldset#id_dropzoneheader select').on('change', function(e) { - var name = e.target.getAttribute('name'); - var draginstanceno = this.form.from_name_with_index(name).indexes[0]; - var old = this.doc.drag_item(draginstanceno); - if (old !== null) { - old.remove(true); - } - this.draw_dd_area(); - }, this); - - for (var i = 0; i < this.form.get_form_value('noitems', []); i++) { - // Change to group selector. - Y.all('#fgroup_id_drags_' + i + ' select.draggroup').on('change', this.redraw_dd_area, this); - Y.all('#fgroup_id_drags_' + i + ' select.dragitemtype').on('change', this.redraw_dd_area, this); - Y.all('fieldset#draggableitemheader_' + i + ' input[type="text"]') - .on('blur', this.set_options_for_drag_item_selectors, this); - // Change to infinite checkbox. - Y.all('fieldset#draggableitemheader_' + i + ' input[type="checkbox"]') - .on('change', this.set_options_for_drag_item_selectors, this); - } - // Event on file picker new file selection. - Y.after(function(e) { - var name = this.fp.name(e.id); - if (name !== 'bgimage') { - this.doc.drag_items().remove(true); - } - this.draw_dd_area(); - }, M.form_filepicker, 'callback', this); - }, - - /** - * Redraws drag and drop preview area. - * - * @method redraw_dd_area - */ - redraw_dd_area: function() { - this.doc.drag_items().remove(true); - this.draw_dd_area(); - }, - - update_visibility_of_file_pickers: function() { - for (var i = 0; i < this.form.get_form_value('noitems', []); i++) { - if ('image' === this.form.get_form_value('drags', [i, 'dragitemtype'])) { - Y.one('input#id_dragitem_' + i).get('parentNode').get('parentNode') - .setStyle('display', 'block'); - } else { - Y.one('input#id_dragitem_' + i).get('parentNode').get('parentNode') - .setStyle('display', 'none'); - } - } - }, - - reposition_drags_for_form: function() { - this.doc.drag_items().each(function(drag) { - var draginstanceno = drag.getData('draginstanceno'); - this.reposition_drag_for_form(draginstanceno); - }, this); - M.util.js_complete(this.pendingid); - }, - - reposition_drag_for_form: function(draginstanceno) { - var drag = this.doc.drag_item(draginstanceno); - if (null !== drag && !drag.hasClass('yui3-dd-dragging')) { - var fromform = [this.form.get_form_value('drops', [draginstanceno, 'xleft']), - this.form.get_form_value('drops', [draginstanceno, 'ytop'])]; - if (fromform[0] === '' && fromform[1] === '') { - var dragitemno = drag.getData('dragitemno'); - drag.setXY(this.doc.drag_item_home(dragitemno).getXY()); - } else { - drag.setXY(this.convert_to_window_xy(fromform)); - } - } - }, - set_drag_xy: function(draginstanceno, xy) { - xy = this.constrain_xy(draginstanceno, this.convert_to_bg_img_xy(xy)); - this.form.set_form_value('drops', [draginstanceno, 'xleft'], Math.round(xy[0])); - this.form.set_form_value('drops', [draginstanceno, 'ytop'], Math.round(xy[1])); - }, - reset_drag_xy: function(draginstanceno) { - this.form.set_form_value('drops', [draginstanceno, 'xleft'], ''); - this.form.set_form_value('drops', [draginstanceno, 'ytop'], ''); - }, - - // make sure xy value is not out of bounds of bg image - constrain_xy: function(draginstanceno, bgimgxy) { - var drag = this.doc.drag_item(draginstanceno); - var xleftconstrained = - Math.min(bgimgxy[0], this.doc.bg_img().get('width') - drag.get('offsetWidth')); - var ytopconstrained = - Math.min(bgimgxy[1], this.doc.bg_img().get('height') - drag.get('offsetHeight')); - xleftconstrained = Math.max(xleftconstrained, 0); - ytopconstrained = Math.max(ytopconstrained, 0); - return [xleftconstrained, ytopconstrained]; - }, - convert_to_bg_img_xy: function(windowxy) { - return [Number(windowxy[0]) - this.doc.bg_img().getX() - 1, - Number(windowxy[1]) - this.doc.bg_img().getY() - 1]; - }, - - /** - * Low level operations on form. - */ - form: { - to_name_with_index: function(name, indexes) { - var indexstring = name; - for (var i = 0; i < indexes.length; i++) { - indexstring = indexstring + '[' + indexes[i] + ']'; - } - return indexstring; - }, - get_el: function(name, indexes) { - var form = document.getElementById('mform1'); - return form.elements[this.to_name_with_index(name, indexes)]; - }, - get_form_value: function(name, indexes) { - var el = this.get_el(name, indexes); - if (el.type === 'checkbox') { - return el.checked; - } else { - return el.value; - } - }, - set_form_value: function(name, indexes, value) { - var el = this.get_el(name, indexes); - if (el.type === 'checkbox') { - el.checked = value; - } else { - el.value = value; - } - }, - from_name_with_index: function(name) { - var toreturn = {}; - toreturn.indexes = []; - var bracket = name.indexOf('['); - toreturn.name = name.substring(0, bracket); - while (bracket !== -1) { - var end = name.indexOf(']', bracket + 1); - toreturn.indexes.push(name.substring(bracket + 1, end)); - bracket = name.indexOf('[', end + 1); - } - return toreturn; - } - }, - - file_pickers: function() { - var draftitemidstoname; - var nametoparentnode; - if (draftitemidstoname === undefined) { - draftitemidstoname = {}; - nametoparentnode = {}; - var filepickers = Y.all('form.mform input.filepickerhidden'); - filepickers.each(function(filepicker) { - draftitemidstoname[filepicker.get('value')] = filepicker.get('name'); - nametoparentnode[filepicker.get('name')] = filepicker.get('parentNode'); - }, this); - } - var toreturn = { - file: function(name) { - var parentnode = nametoparentnode[name]; - var fileanchor = parentnode.one('div.filepicker-filelist a'); - if (fileanchor) { - return {href: fileanchor.get('href'), name: fileanchor.get('innerHTML')}; - } else { - return {href: null, name: null}; - } - }, - name: function(draftitemid) { - return draftitemidstoname[draftitemid]; - } - }; - return toreturn; - } -}, {NAME: DDIMAGEORTEXTFORMNAME, ATTRS: {maxsizes: {value: null}}}); -M.qtype_ddimageortext = M.qtype_ddimageortext || {}; -M.qtype_ddimageortext.init_form = function(config) { - return new DDIMAGEORTEXT_FORM(config); -}; - - -}, '@VERSION@', {"requires": ["moodle-qtype_ddimageortext-dd", "form_filepicker"]}); diff --git a/question/type/ddimageortext/yui/src/ddimageortext/build.json b/question/type/ddimageortext/yui/src/ddimageortext/build.json deleted file mode 100644 index 00d07c6bf8c29..0000000000000 --- a/question/type/ddimageortext/yui/src/ddimageortext/build.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "moodle-qtype_ddimageortext-dd", - "builds": { - "moodle-qtype_ddimageortext-dd": { - "jsfiles": [ - "ddimageortext.js" - ] - } - } -} diff --git a/question/type/ddimageortext/yui/src/ddimageortext/js/ddimageortext.js b/question/type/ddimageortext/yui/src/ddimageortext/js/ddimageortext.js deleted file mode 100644 index 979efc6af1975..0000000000000 --- a/question/type/ddimageortext/yui/src/ddimageortext/js/ddimageortext.js +++ /dev/null @@ -1,541 +0,0 @@ -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -var DDIMAGEORTEXTDDNAME = 'ddimageortext_dd'; -var DDIMAGEORTEXT_DD = function() { - DDIMAGEORTEXT_DD.superclass.constructor.apply(this, arguments); -}; - -/** - * This is the base class for the question rendering and question editing form code. - */ -Y.extend(DDIMAGEORTEXT_DD, Y.Base, { - doc: null, - polltimer: null, - afterimageloaddone: false, - poll_for_image_load: function(e, waitforimageconstrain, pause, doafterwords) { - if (this.afterimageloaddone) { - return; - } - var bgdone = this.doc.bg_img().get('complete'); - if (waitforimageconstrain) { - bgdone = bgdone && this.doc.bg_img().hasClass('constrained'); - } - var alldragsloaded = !this.doc.drag_item_homes().some(function(dragitemhome) { - // in 'some' loop returning true breaks the loop and is passed as return value from - // 'some' else returns false. Can be though of as equivalent to ||. - if (dragitemhome.get('tagName') !== 'IMG') { - return false; - } - var done = (dragitemhome.get('complete')); - if (waitforimageconstrain) { - done = done && dragitemhome.hasClass('constrained'); - } - return !done; - }); - if (bgdone && alldragsloaded) { - if (this.polltimer !== null) { - this.polltimer.cancel(); - this.polltimer = null; - } - this.doc.drag_item_homes().detach('load', this.poll_for_image_load); - this.doc.bg_img().detach('load', this.poll_for_image_load); - if (pause !== 0) { - Y.later(pause, this, doafterwords); - } else { - doafterwords.call(this); - } - this.afterimageloaddone = true; - } else if (this.polltimer === null) { - var pollarguments = [null, waitforimageconstrain, pause, doafterwords]; - this.polltimer = - Y.later(1000, this, this.poll_for_image_load, pollarguments, true); - } - }, - /** - * Object to encapsulate operations on dd area. - */ - doc_structure: function(mainobj) { - var topnode = Y.one(this.get('topnode')); - var dragitemsarea = topnode.one('div.dragitems'); - var dropbgarea = topnode.one('div.droparea'); - return { - top_node: function() { - return topnode; - }, - drag_items: function() { - return dragitemsarea.all('.drag'); - }, - drop_zones: function() { - return topnode.all('div.dropzones div.dropzone'); - }, - drop_zone_group: function(groupno) { - return topnode.all('div.dropzones div.group' + groupno); - }, - drag_items_cloned_from: function(dragitemno) { - return dragitemsarea.all('.dragitems' + dragitemno); - }, - drag_item: function(draginstanceno) { - return dragitemsarea.one('.draginstance' + draginstanceno); - }, - drag_items_in_group: function(groupno) { - return dragitemsarea.all('.drag.group' + groupno); - }, - drag_item_homes: function() { - return dragitemsarea.all('.draghome'); - }, - bg_img: function() { - return topnode.one('.dropbackground'); - }, - load_bg_img: function(url) { - dropbgarea.setContent(''); - this.bg_img().on('load', this.on_image_load, this, 'bg_image'); - }, - add_or_update_drag_item_home: function(dragitemno, url, alt, group) { - var oldhome = this.drag_item_home(dragitemno); - var classes = 'draghome dragitemhomes' + dragitemno + ' group' + group; - var imghtml = '' + alt + ''; - var divhtml = '
' + alt + '
'; - if (oldhome === null) { - if (url) { - dragitemsarea.append(imghtml); - } else if (alt !== '') { - dragitemsarea.append(divhtml); - } - } else { - if (url) { - dragitemsarea.insert(imghtml, oldhome); - } else if (alt !== '') { - dragitemsarea.insert(divhtml, oldhome); - } - oldhome.remove(true); - } - var newlycreated = dragitemsarea.one('.dragitemhomes' + dragitemno); - if (newlycreated !== null) { - newlycreated.setData('groupno', group); - newlycreated.setData('dragitemno', dragitemno); - } - }, - drag_item_home: function(dragitemno) { - return dragitemsarea.one('.dragitemhomes' + dragitemno); - }, - get_classname_numeric_suffix: function(node, prefix) { - var classes = node.getAttribute('class'); - if (classes !== '') { - var classesarr = classes.split(' '); - for (var index = 0; index < classesarr.length; index++) { - var patt1 = new RegExp('^' + prefix + '([0-9])+$'); - if (patt1.test(classesarr[index])) { - var patt2 = new RegExp('([0-9])+$'); - var match = patt2.exec(classesarr[index]); - return +match[0]; - } - } - } - throw 'Prefix "' + prefix + '" not found in class names.'; - }, - clone_new_drag_item: function(draginstanceno, dragitemno) { - var draghome = this.drag_item_home(dragitemno); - if (draghome === null) { - return null; - } - var drag = draghome.cloneNode(true); - drag.removeClass('dragitemhomes' + dragitemno); - drag.addClass('dragitems' + dragitemno); - drag.addClass('draginstance' + draginstanceno); - drag.removeClass('draghome'); - drag.addClass('drag'); - drag.setStyles({'visibility': 'visible', 'position': 'absolute'}); - drag.setData('draginstanceno', draginstanceno); - drag.setData('dragitemno', dragitemno); - draghome.get('parentNode').appendChild(drag); - return drag; - }, - draggable_for_question: function(drag, group, choice) { - new Y.DD.Drag({ - node: drag, - dragMode: 'point', - groups: [group] - }).plug(Y.Plugin.DDConstrained, {constrain2node: topnode}); - - drag.setData('group', group); - drag.setData('choice', choice); - }, - draggable_for_form: function(drag) { - var dd = new Y.DD.Drag({ - node: drag, - dragMode: 'point' - }).plug(Y.Plugin.DDConstrained, {constrain2node: topnode}); - dd.on('drag:end', function(e) { - var dragnode = e.target.get('node'); - var draginstanceno = dragnode.getData('draginstanceno'); - var gooddrop = dragnode.getData('gooddrop'); - - if (!gooddrop) { - mainobj.reset_drag_xy(draginstanceno); - } else { - mainobj.set_drag_xy(draginstanceno, [e.pageX, e.pageY]); - } - }, this); - dd.on('drag:start', function(e) { - var drag = e.target; - drag.get('node').setData('gooddrop', false); - }, this); - - } - - }; - }, - - update_padding_sizes_all: function() { - for (var groupno = 1; groupno <= 8; groupno++) { - this.update_padding_size_for_group(groupno); - } - }, - update_padding_size_for_group: function(groupno) { - var groupitems = this.doc.top_node().all('.draghome.group' + groupno); - if (groupitems.size() !== 0) { - var maxwidth = 0; - var maxheight = 0; - groupitems.each(function(item) { - maxwidth = Math.max(maxwidth, item.get('clientWidth')); - maxheight = Math.max(maxheight, item.get('clientHeight')); - }, this); - groupitems.each(function(item) { - var margintopbottom = Math.round((10 + maxheight - item.get('clientHeight')) / 2); - var marginleftright = Math.round((10 + maxwidth - item.get('clientWidth')) / 2); - item.setStyle('padding', margintopbottom + 'px ' + marginleftright + 'px ' + - margintopbottom + 'px ' + marginleftright + 'px'); - }, this); - this.doc.drop_zone_group(groupno).setStyles({'width': maxwidth + 10, - 'height': maxheight + 10}); - } - }, - convert_to_window_xy: function(bgimgxy) { - return [Number(bgimgxy[0]) + this.doc.bg_img().getX() + 1, - Number(bgimgxy[1]) + this.doc.bg_img().getY() + 1]; - } -}, { - NAME: DDIMAGEORTEXTDDNAME, - ATTRS: { - drops: {value: null}, - readonly: {value: false}, - topnode: {value: null} - } -}); - -M.qtype_ddimageortext = M.qtype_ddimageortext || {}; -M.qtype_ddimageortext.dd_base_class = DDIMAGEORTEXT_DD; - -var DDIMAGEORTEXTQUESTIONNAME = 'ddimageortext_question'; -var DDIMAGEORTEXT_QUESTION = function() { - DDIMAGEORTEXT_QUESTION.superclass.constructor.apply(this, arguments); -}; -/** - * This is the code for question rendering. - */ -Y.extend(DDIMAGEORTEXT_QUESTION, M.qtype_ddimageortext.dd_base_class, { - passiveSupported: false, - pendingid: '', - initializer: function() { - this.pendingid = 'qtype_ddimageortext-' + Math.random().toString(36).slice(2); // Random string. - M.util.js_pending(this.pendingid); - this.doc = this.doc_structure(this); - this.poll_for_image_load(null, false, 10, this.create_all_drag_and_drops); - this.doc.bg_img().after('load', this.poll_for_image_load, this, - false, 10, this.create_all_drag_and_drops); - this.doc.drag_item_homes().after('load', this.poll_for_image_load, this, - false, 10, this.create_all_drag_and_drops); - if (!this.get('readonly')) { - Y.later(500, this, this.reposition_drags_for_question, true); - } else { - Y.one('window').on('resize', function() { - this.reposition_drags_for_question(); - }, this); - } - this.checkPassiveSupported(); - }, - - /** - * prevent_touchmove_from_scrolling allows users of touch screen devices to - * use drag and drop and normal scrolling at the same time. I.e. when - * touching and dragging a draggable item, the screen does not scroll, but - * you can scroll by touching other area of the screen apart from the - * draggable items. - */ - prevent_touchmove_from_scrolling: function(drag) { - var touchmove = (Y.UA.ie) ? 'MSPointerMove' : 'touchmove'; - var eventHandler = function(event) { - event.preventDefault(); - }; - var dragId = drag.get('id'); - var el = document.getElementById(dragId); - // Note do not dynamically add events within another event, as this causes issues on iOS11.3. - // See https://github.com/atlassian/react-beautiful-dnd/issues/413 and - // https://bugs.webkit.org/show_bug.cgi?id=184250 for fuller explanation. - el.addEventListener(touchmove, eventHandler, this.passiveSupported ? {passive: false, capture: true} : false); - }, - - /** - * Some older browsers do not support passing an options object to addEventListener. - * This is a check from https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener. - */ - checkPassiveSupported: function() { - try { - var options = Object.defineProperty({}, 'passive', { - get: function() { - this.passiveSupported = true; - }.bind(this) - }); - window.addEventListener('test', options, options); - window.removeEventListener('test', options, options); - } catch (err) { - this.passiveSupported = false; - } - }, - - create_all_drag_and_drops: function() { - this.init_drops(); - this.update_padding_sizes_all(); - var i = 0; - this.doc.drag_item_homes().each(function(dragitemhome) { - var dragitemno = Number(this.doc.get_classname_numeric_suffix(dragitemhome, 'dragitemhomes')); - var choice = +this.doc.get_classname_numeric_suffix(dragitemhome, 'choice'); - var group = +this.doc.get_classname_numeric_suffix(dragitemhome, 'group'); - var groupsize = this.doc.drop_zone_group(group).size(); - var dragnode = this.doc.clone_new_drag_item(i, dragitemno); - i++; - if (!this.get('readonly')) { - this.doc.draggable_for_question(dragnode, group, choice); - - // Prevent scrolling whilst dragging on Adroid devices. - this.prevent_touchmove_from_scrolling(dragnode); - } - if (dragnode.hasClass('infinite')) { - var dragstocreate = groupsize - 1; - while (dragstocreate > 0) { - dragnode = this.doc.clone_new_drag_item(i, dragitemno); - i++; - if (!this.get('readonly')) { - this.doc.draggable_for_question(dragnode, group, choice); - - // Prevent scrolling whilst dragging on Adroid devices. - this.prevent_touchmove_from_scrolling(dragnode); - } - dragstocreate--; - } - } - }, this); - this.reposition_drags_for_question(); - if (!this.get('readonly')) { - this.doc.drop_zones().set('tabIndex', 0); - this.doc.drop_zones().each( - function(v) { - v.on('dragchange', this.drop_zone_key_press, this); - }, this); - } - M.util.js_complete(this.pendingid); - }, - drop_zone_key_press: function(e) { - switch (e.direction) { - case 'next' : - this.place_next_drag_in(e.target); - break; - case 'previous' : - this.place_previous_drag_in(e.target); - break; - case 'remove' : - this.remove_drag_from_drop(e.target); - break; - } - e.preventDefault(); - this.reposition_drags_for_question(); - }, - place_next_drag_in: function(drop) { - this.search_for_unplaced_drop_choice(drop, 1); - }, - place_previous_drag_in: function(drop) { - this.search_for_unplaced_drop_choice(drop, -1); - }, - search_for_unplaced_drop_choice: function(drop, direction) { - var next; - var current = this.current_drag_in_drop(drop); - if ('' === current) { - if (direction === 1) { - next = 1; - } else { - next = 1; - var groupno = drop.getData('group'); - this.doc.drag_items_in_group(groupno).each(function(drag) { - next = Math.max(next, drag.getData('choice')); - }, this); - } - } else { - next = +current + direction; - } - var drag; - do { - if (this.get_choices_for_drop(next, drop).size() === 0) { - this.remove_drag_from_drop(drop); - return; - } else { - drag = this.get_unplaced_choice_for_drop(next, drop); - } - next = next + direction; - } while (drag === null); - this.place_drag_in_drop(drag, drop); - }, - current_drag_in_drop: function(drop) { - var inputid = drop.getData('inputid'); - var inputnode = Y.one('input#' + inputid); - return inputnode.get('value'); - }, - remove_drag_from_drop: function(drop) { - this.place_drag_in_drop(null, drop); - }, - place_drag_in_drop: function(drag, drop) { - var inputid = drop.getData('inputid'); - var inputnode = Y.one('input#' + inputid); - if (drag !== null) { - inputnode.set('value', drag.getData('choice')); - } else { - inputnode.set('value', ''); - } - }, - reposition_drags_for_question: function(dotimeout) { - this.doc.drag_items().removeClass('placed'); - this.doc.drag_items().each(function(dragitem) { - if (dragitem.dd !== undefined) { - dragitem.dd.detachAll('drag:start'); - } - }, this); - this.doc.drop_zones().each(function(dropzone) { - var relativexy = dropzone.getData('xy'); - dropzone.setXY(this.convert_to_window_xy(relativexy)); - var inputcss = 'input#' + dropzone.getData('inputid'); - var input = this.doc.top_node().one(inputcss); - var choice = input.get('value'); - if (choice !== "") { - var dragitem = this.get_unplaced_choice_for_drop(choice, dropzone); - if (dragitem !== null) { - dragitem.setXY(dropzone.getXY()); - dragitem.addClass('placed'); - if (dragitem.dd !== undefined) { - dragitem.dd.once('drag:start', function(e, input) { - input.set('value', ''); - e.target.get('node').removeClass('placed'); - }, this, input); - } - } - } - }, this); - this.doc.drag_items().each(function(dragitem) { - if (!dragitem.hasClass('placed') && !dragitem.hasClass('yui3-dd-dragging')) { - var dragitemhome = this.doc.drag_item_home(dragitem.getData('dragitemno')); - dragitem.setXY(dragitemhome.getXY()); - } - }, this); - if (dotimeout) { - Y.later(500, this, this.reposition_drags_for_question, true); - } - }, - get_choices_for_drop: function(choice, drop) { - var group = drop.getData('group'); - return this.doc.top_node().all( - 'div.dragitemgroup' + group + ' .choice' + choice + '.drag'); - }, - get_unplaced_choice_for_drop: function(choice, drop) { - var dragitems = this.get_choices_for_drop(choice, drop); - var dragitem = null; - dragitems.some(function(d) { - if (this.get('readonly') || (!d.hasClass('placed') && !d.hasClass('yui3-dd-dragging'))) { - dragitem = d; - return true; - } else { - return false; - } - }); - return dragitem; - }, - init_drops: function() { - var dropareas = this.doc.top_node().one('div.dropzones'); - var groupnodes = {}; - for (var groupno = 1; groupno <= 8; groupno++) { - var groupnode = Y.Node.create('
'); - dropareas.append(groupnode); - groupnodes[groupno] = groupnode; - } - var drop_hit_handler = function(e) { - var drag = e.drag.get('node'); - var drop = e.drop.get('node'); - if (Number(drop.getData('group')) === drag.getData('group')) { - this.place_drag_in_drop(drag, drop); - } - }; - for (var dropno in this.get('drops')) { - var drop = this.get('drops')[dropno]; - var nodeclass = 'dropzone group' + drop.group + ' place' + dropno; - var title = drop.text.replace('"', '\"'); - if (!title) { - title = M.util.get_string('blank', 'qtype_ddimageortext'); - } - var dropnodehtml = '
' + - '' + title + ' 
'; - var dropnode = Y.Node.create(dropnodehtml); - groupnodes[drop.group].append(dropnode); - dropnode.setStyles({'opacity': 0.5}); - dropnode.setData('xy', drop.xy); - dropnode.setData('place', dropno); - dropnode.setData('inputid', drop.fieldname.replace(':', '_')); - dropnode.setData('group', drop.group); - var dropdd = new Y.DD.Drop({ - node: dropnode, groups: [drop.group]}); - dropdd.on('drop:hit', drop_hit_handler, this); - } - } -}, {NAME: DDIMAGEORTEXTQUESTIONNAME, ATTRS: {}}); - -Y.Event.define('dragchange', { - // Webkit and IE repeat keydown when you hold down arrow keys. - // Opera links keypress to page scroll; others keydown. - // Firefox prevents page scroll via preventDefault() on either - // keydown or keypress. - _event: (Y.UA.webkit || Y.UA.ie) ? 'keydown' : 'keypress', - - _keys: { - '32': 'next', // Space - '37': 'previous', // Left arrow - '38': 'previous', // Up arrow - '39': 'next', // Right arrow - '40': 'next', // Down arrow - '27': 'remove' // Escape - }, - - _keyHandler: function(e, notifier) { - if (this._keys[e.keyCode]) { - e.direction = this._keys[e.keyCode]; - notifier.fire(e); - } - }, - - on: function(node, sub, notifier) { - sub._detacher = node.on(this._event, this._keyHandler, - this, notifier); - } -}); - -M.qtype_ddimageortext.init_question = function(config) { - return new DDIMAGEORTEXT_QUESTION(config); -}; diff --git a/question/type/ddimageortext/yui/src/ddimageortext/meta/ddimageortext.json b/question/type/ddimageortext/yui/src/ddimageortext/meta/ddimageortext.json deleted file mode 100644 index a9e0af6b4d244..0000000000000 --- a/question/type/ddimageortext/yui/src/ddimageortext/meta/ddimageortext.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "moodle-qtype_ddimageortext-dd": { - "requires": [ - "node", - "dd", - "dd-drop", - "dd-constrain" - ] - } -} diff --git a/question/type/ddimageortext/yui/src/form/build.json b/question/type/ddimageortext/yui/src/form/build.json deleted file mode 100644 index 8e57acce72f5b..0000000000000 --- a/question/type/ddimageortext/yui/src/form/build.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "moodle-qtype_ddimageortext-form", - "builds": { - "moodle-qtype_ddimageortext-form": { - "jsfiles": [ - "form.js" - ] - } - } -} diff --git a/question/type/ddimageortext/yui/src/form/js/form.js b/question/type/ddimageortext/yui/src/form/js/form.js deleted file mode 100644 index deea439051b44..0000000000000 --- a/question/type/ddimageortext/yui/src/form/js/form.js +++ /dev/null @@ -1,364 +0,0 @@ -// This file is part of Moodle - http://moodle.org/ -// -// Moodle is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Moodle is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Moodle. If not, see . - -/** - * This is the question editing form code. - */ -var DDIMAGEORTEXTFORMNAME = 'moodle-qtype_ddimageortext-form'; -var DDIMAGEORTEXT_FORM = function() { - DDIMAGEORTEXT_FORM.superclass.constructor.apply(this, arguments); -}; - -Y.extend(DDIMAGEORTEXT_FORM, M.qtype_ddimageortext.dd_base_class, { - pendingid: '', - fp: null, - - initializer: function() { - this.pendingid = 'qtype_ddimageortext-form-' + Math.random().toString(36).slice(2); // Random string. - M.util.js_pending(this.pendingid); - this.fp = this.file_pickers(); - var tn = Y.one(this.get('topnode')); - tn.one('div.fcontainer').append('
' + - '
'); - this.doc = this.doc_structure(this); - this.draw_dd_area(); - }, - - draw_dd_area: function() { - var bgimageurl = this.fp.file('bgimage').href; - this.stop_selector_events(); - this.set_options_for_drag_item_selectors(); - if (bgimageurl !== null) { - this.doc.load_bg_img(bgimageurl); - this.load_drag_homes(); - - var drop = new Y.DD.Drop({ - node: this.doc.bg_img() - }); - // Listen for a drop:hit on the background image - drop.on('drop:hit', function(e) { - e.drag.get('node').setData('gooddrop', true); - }); - - this.afterimageloaddone = false; - this.doc.bg_img().on('load', this.constrain_image_size, this, 'bgimage'); - this.doc.drag_item_homes() - .on('load', this.constrain_image_size, this, 'dragimage'); - this.doc.bg_img().after('load', this.poll_for_image_load, this, - true, 0, this.after_all_images_loaded); - this.doc.drag_item_homes().after('load', this.poll_for_image_load, this, - true, 0, this.after_all_images_loaded); - } else { - this.setup_form_events(); - M.util.js_complete(this.pendingid); - } - this.update_visibility_of_file_pickers(); - }, - - after_all_images_loaded: function() { - this.update_padding_sizes_all(); - this.update_drag_instances(); - this.reposition_drags_for_form(); - this.set_options_for_drag_item_selectors(); - this.setup_form_events(); - Y.later(500, this, this.reposition_drags_for_form, [], true); - }, - - constrain_image_size: function(e, imagetype) { - var maxsize = this.get('maxsizes')[imagetype]; - var reduceby = Math.max(e.target.get('width') / maxsize.width, - e.target.get('height') / maxsize.height); - if (reduceby > 1) { - e.target.set('width', Math.floor(e.target.get('width') / reduceby)); - } - e.target.addClass('constrained'); - e.target.detach('load', this.constrain_image_size); - }, - - load_drag_homes: function() { - // Set up drag items homes. - for (var i = 0; i < this.form.get_form_value('noitems', []); i++) { - this.load_drag_home(i); - } - }, - - load_drag_home: function(dragitemno) { - var url = null; - if ('image' === this.form.get_form_value('drags', [dragitemno, 'dragitemtype'])) { - url = this.fp.file(this.form.to_name_with_index('dragitem', [dragitemno])).href; - } - this.doc.add_or_update_drag_item_home(dragitemno, url, - this.form.get_form_value('draglabel', [dragitemno]), - this.form.get_form_value('drags', [dragitemno, 'draggroup'])); - }, - - update_drag_instances: function() { - // Set up drop zones. - for (var i = 0; i < this.form.get_form_value('nodropzone', []); i++) { - var dragitemno = this.form.get_form_value('drops', [i, 'choice']); - if (dragitemno !== '0' && (this.doc.drag_item(i) === null)) { - var drag = this.doc.clone_new_drag_item(i, dragitemno - 1); - if (drag !== null) { - this.doc.draggable_for_form(drag); - } - } - } - }, - set_options_for_drag_item_selectors: function() { - var dragitemsoptions = {'0': ''}; - for (var i = 0; i < this.form.get_form_value('noitems', []); i++) { - var label = this.form.get_form_value('draglabel', [i]); - var file = this.fp.file(this.form.to_name_with_index('dragitem', [i])); - if ('image' === this.form.get_form_value('drags', [i, 'dragitemtype']) - && file.name !== null) { - dragitemsoptions[i + 1] = (i + 1) + '. ' + label + ' (' + file.name + ')'; - } else if (label !== '') { - dragitemsoptions[i + 1] = (i + 1) + '. ' + label; - } - } - for (i = 0; i < this.form.get_form_value('nodropzone', []); i++) { - var selector = Y.one('#id_drops_' + i + '_choice'); - var selectedvalue = selector.get('value'); - selector.all('option').remove(true); - for (var value in dragitemsoptions) { - value = +value; - var option = ''; - selector.append(option); - var optionnode = selector.one('option[value="' + value + '"]'); - if (value === +selectedvalue) { - optionnode.set('selected', true); - } else { - if (value !== 0) { // No item option is always selectable. - var cbel = Y.one('#id_drags_' + (value - 1) + '_infinite'); - if (cbel && !cbel.get('checked')) { - if (this.item_is_allocated_to_dropzone(value)) { - optionnode.set('disabled', true); - } - } - } - } - } - } - }, - - stop_selector_events: function() { - Y.all('fieldset#id_dropzoneheader select').detachAll(); - }, - - /** - * Checks if the specified drag item is allocated to a dropzone. - * - * @method item_is_allocated_to_dropzone - * @param {Number} value of the drag item to check - * @return {Boolean} true if item is allocated to dropzone - */ - item_is_allocated_to_dropzone: function(itemvalue) { - return Y.all('fieldset#id_dropzoneheader select').some(function(selectNode) { - return Number(selectNode.get('value')) === itemvalue; - }); - }, - - setup_form_events: function() { - // Events triggered by changes to form data. - - // X and y coordinates. - Y.all('fieldset#id_dropzoneheader input').on('blur', function(e) { - var name = e.target.getAttribute('name'); - var draginstanceno = this.form.from_name_with_index(name).indexes[0]; - var fromform = [this.form.get_form_value('drops', [draginstanceno, 'xleft']), - this.form.get_form_value('drops', [draginstanceno, 'ytop'])]; - var constrainedxy = this.constrain_xy(draginstanceno, fromform); - this.form.set_form_value('drops', [draginstanceno, 'xleft'], constrainedxy[0]); - this.form.set_form_value('drops', [draginstanceno, 'ytop'], constrainedxy[1]); - }, this); - - // Change in selected item. - Y.all('fieldset#id_dropzoneheader select').on('change', function(e) { - var name = e.target.getAttribute('name'); - var draginstanceno = this.form.from_name_with_index(name).indexes[0]; - var old = this.doc.drag_item(draginstanceno); - if (old !== null) { - old.remove(true); - } - this.draw_dd_area(); - }, this); - - for (var i = 0; i < this.form.get_form_value('noitems', []); i++) { - // Change to group selector. - Y.all('#fgroup_id_drags_' + i + ' select.draggroup').on('change', this.redraw_dd_area, this); - Y.all('#fgroup_id_drags_' + i + ' select.dragitemtype').on('change', this.redraw_dd_area, this); - Y.all('fieldset#draggableitemheader_' + i + ' input[type="text"]') - .on('blur', this.set_options_for_drag_item_selectors, this); - // Change to infinite checkbox. - Y.all('fieldset#draggableitemheader_' + i + ' input[type="checkbox"]') - .on('change', this.set_options_for_drag_item_selectors, this); - } - // Event on file picker new file selection. - Y.after(function(e) { - var name = this.fp.name(e.id); - if (name !== 'bgimage') { - this.doc.drag_items().remove(true); - } - this.draw_dd_area(); - }, M.form_filepicker, 'callback', this); - }, - - /** - * Redraws drag and drop preview area. - * - * @method redraw_dd_area - */ - redraw_dd_area: function() { - this.doc.drag_items().remove(true); - this.draw_dd_area(); - }, - - update_visibility_of_file_pickers: function() { - for (var i = 0; i < this.form.get_form_value('noitems', []); i++) { - if ('image' === this.form.get_form_value('drags', [i, 'dragitemtype'])) { - Y.one('input#id_dragitem_' + i).get('parentNode').get('parentNode') - .setStyle('display', 'block'); - } else { - Y.one('input#id_dragitem_' + i).get('parentNode').get('parentNode') - .setStyle('display', 'none'); - } - } - }, - - reposition_drags_for_form: function() { - this.doc.drag_items().each(function(drag) { - var draginstanceno = drag.getData('draginstanceno'); - this.reposition_drag_for_form(draginstanceno); - }, this); - M.util.js_complete(this.pendingid); - }, - - reposition_drag_for_form: function(draginstanceno) { - var drag = this.doc.drag_item(draginstanceno); - if (null !== drag && !drag.hasClass('yui3-dd-dragging')) { - var fromform = [this.form.get_form_value('drops', [draginstanceno, 'xleft']), - this.form.get_form_value('drops', [draginstanceno, 'ytop'])]; - if (fromform[0] === '' && fromform[1] === '') { - var dragitemno = drag.getData('dragitemno'); - drag.setXY(this.doc.drag_item_home(dragitemno).getXY()); - } else { - drag.setXY(this.convert_to_window_xy(fromform)); - } - } - }, - set_drag_xy: function(draginstanceno, xy) { - xy = this.constrain_xy(draginstanceno, this.convert_to_bg_img_xy(xy)); - this.form.set_form_value('drops', [draginstanceno, 'xleft'], Math.round(xy[0])); - this.form.set_form_value('drops', [draginstanceno, 'ytop'], Math.round(xy[1])); - }, - reset_drag_xy: function(draginstanceno) { - this.form.set_form_value('drops', [draginstanceno, 'xleft'], ''); - this.form.set_form_value('drops', [draginstanceno, 'ytop'], ''); - }, - - // make sure xy value is not out of bounds of bg image - constrain_xy: function(draginstanceno, bgimgxy) { - var drag = this.doc.drag_item(draginstanceno); - var xleftconstrained = - Math.min(bgimgxy[0], this.doc.bg_img().get('width') - drag.get('offsetWidth')); - var ytopconstrained = - Math.min(bgimgxy[1], this.doc.bg_img().get('height') - drag.get('offsetHeight')); - xleftconstrained = Math.max(xleftconstrained, 0); - ytopconstrained = Math.max(ytopconstrained, 0); - return [xleftconstrained, ytopconstrained]; - }, - convert_to_bg_img_xy: function(windowxy) { - return [Number(windowxy[0]) - this.doc.bg_img().getX() - 1, - Number(windowxy[1]) - this.doc.bg_img().getY() - 1]; - }, - - /** - * Low level operations on form. - */ - form: { - to_name_with_index: function(name, indexes) { - var indexstring = name; - for (var i = 0; i < indexes.length; i++) { - indexstring = indexstring + '[' + indexes[i] + ']'; - } - return indexstring; - }, - get_el: function(name, indexes) { - var form = document.getElementById('mform1'); - return form.elements[this.to_name_with_index(name, indexes)]; - }, - get_form_value: function(name, indexes) { - var el = this.get_el(name, indexes); - if (el.type === 'checkbox') { - return el.checked; - } else { - return el.value; - } - }, - set_form_value: function(name, indexes, value) { - var el = this.get_el(name, indexes); - if (el.type === 'checkbox') { - el.checked = value; - } else { - el.value = value; - } - }, - from_name_with_index: function(name) { - var toreturn = {}; - toreturn.indexes = []; - var bracket = name.indexOf('['); - toreturn.name = name.substring(0, bracket); - while (bracket !== -1) { - var end = name.indexOf(']', bracket + 1); - toreturn.indexes.push(name.substring(bracket + 1, end)); - bracket = name.indexOf('[', end + 1); - } - return toreturn; - } - }, - - file_pickers: function() { - var draftitemidstoname; - var nametoparentnode; - if (draftitemidstoname === undefined) { - draftitemidstoname = {}; - nametoparentnode = {}; - var filepickers = Y.all('form.mform input.filepickerhidden'); - filepickers.each(function(filepicker) { - draftitemidstoname[filepicker.get('value')] = filepicker.get('name'); - nametoparentnode[filepicker.get('name')] = filepicker.get('parentNode'); - }, this); - } - var toreturn = { - file: function(name) { - var parentnode = nametoparentnode[name]; - var fileanchor = parentnode.one('div.filepicker-filelist a'); - if (fileanchor) { - return {href: fileanchor.get('href'), name: fileanchor.get('innerHTML')}; - } else { - return {href: null, name: null}; - } - }, - name: function(draftitemid) { - return draftitemidstoname[draftitemid]; - } - }; - return toreturn; - } -}, {NAME: DDIMAGEORTEXTFORMNAME, ATTRS: {maxsizes: {value: null}}}); -M.qtype_ddimageortext = M.qtype_ddimageortext || {}; -M.qtype_ddimageortext.init_form = function(config) { - return new DDIMAGEORTEXT_FORM(config); -}; diff --git a/question/type/ddimageortext/yui/src/form/meta/form.json b/question/type/ddimageortext/yui/src/form/meta/form.json deleted file mode 100644 index bbd022357511a..0000000000000 --- a/question/type/ddimageortext/yui/src/form/meta/form.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "moodle-qtype_ddimageortext-form": { - "requires": [ - "moodle-qtype_ddimageortext-dd", - "form_filepicker" - ] - } -}