From 24c6f2fc8c13c18cc8ed63581a5e9d9f0baef4e6 Mon Sep 17 00:00:00 2001 From: M Kassaei Date: Thu, 29 Jan 2015 17:35:02 +0000 Subject: [PATCH] MDL-47494 ddmarker: Convert the JavaScript to use Shifter. #13314 --- .../moodle-qtype_ddmarker-dd-debug.js | 565 +++++++++++++++++++++ .../moodle-qtype_ddmarker-dd-min.js | 2 + .../moodle-qtype_ddmarker-dd.js | 565 +++++++++++++++++++++ .../moodle-qtype_ddmarker-form-debug.js | 272 ++++++++++ .../moodle-qtype_ddmarker-form-min.js | 1 + .../moodle-qtype_ddmarker-form.js | 272 ++++++++++ question/type/ddmarker/yui/dd/dd.js | 549 -------------------- question/type/ddmarker/yui/form/form.js | 255 ---------- question/type/ddmarker/yui/src/ddmarker/build.json | 10 + .../type/ddmarker/yui/src/ddmarker/js/ddmarker.js | 560 ++++++++++++++++++++ .../ddmarker/yui/src/ddmarker/meta/ddmarker.json | 12 + question/type/ddmarker/yui/src/form/build.json | 10 + question/type/ddmarker/yui/src/form/js/form.js | 267 ++++++++++ question/type/ddmarker/yui/src/form/meta/form.json | 10 + 14 files changed, 2546 insertions(+), 804 deletions(-) create mode 100644 question/type/ddmarker/yui/build/moodle-qtype_ddmarker-dd/moodle-qtype_ddmarker-dd-debug.js create mode 100644 question/type/ddmarker/yui/build/moodle-qtype_ddmarker-dd/moodle-qtype_ddmarker-dd-min.js create mode 100644 question/type/ddmarker/yui/build/moodle-qtype_ddmarker-dd/moodle-qtype_ddmarker-dd.js create mode 100644 question/type/ddmarker/yui/build/moodle-qtype_ddmarker-form/moodle-qtype_ddmarker-form-debug.js create mode 100644 question/type/ddmarker/yui/build/moodle-qtype_ddmarker-form/moodle-qtype_ddmarker-form-min.js create mode 100644 question/type/ddmarker/yui/build/moodle-qtype_ddmarker-form/moodle-qtype_ddmarker-form.js delete mode 100644 question/type/ddmarker/yui/dd/dd.js delete mode 100644 question/type/ddmarker/yui/form/form.js create mode 100644 question/type/ddmarker/yui/src/ddmarker/build.json create mode 100644 question/type/ddmarker/yui/src/ddmarker/js/ddmarker.js create mode 100644 question/type/ddmarker/yui/src/ddmarker/meta/ddmarker.json create mode 100644 question/type/ddmarker/yui/src/form/build.json create mode 100644 question/type/ddmarker/yui/src/form/js/form.js create mode 100644 question/type/ddmarker/yui/src/form/meta/form.json diff --git a/question/type/ddmarker/yui/build/moodle-qtype_ddmarker-dd/moodle-qtype_ddmarker-dd-debug.js b/question/type/ddmarker/yui/build/moodle-qtype_ddmarker-dd/moodle-qtype_ddmarker-dd-debug.js new file mode 100644 index 00000000000..204c67fa0c6 --- /dev/null +++ b/question/type/ddmarker/yui/build/moodle-qtype_ddmarker-dd/moodle-qtype_ddmarker-dd-debug.js @@ -0,0 +1,565 @@ +YUI.add('moodle-qtype_ddmarker-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 DDMARKERDDNAME = 'moodle-qtype_ddmarker-dd'; +var DDMARKER_DD = function() { + DDMARKER_DD.superclass.constructor.apply(this, arguments); +}; +/** + * This is the base class for the question rendering and question editing form code. + */ +Y.extend(DDMARKER_DD, Y.Base, { + doc : null, + polltimer : null, + afterimageloaddone : false, + graphics : null, + 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'); + } + if (bgdone) { + if (this.polltimer !== null) { + this.polltimer.cancel(); + this.polltimer = null; + } + 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 () { + 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; + }, + 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'); + }, + drag_items : function() { + return dragitemsarea.all('.dragitem'); + }, + drag_items_for_choice : function(choiceno) { + return dragitemsarea.all('span.dragitem.choice' + choiceno); + }, + drag_item_for_choice : function(choiceno, itemno) { + return dragitemsarea.one('span.dragitem.choice' + choiceno + + '.item' + itemno); + }, + drag_item_being_dragged : function(choiceno) { + return dragitemsarea.one('span.dragitem.beingdragged.choice' + choiceno); + }, + drag_item_home : function (choiceno) { + return dragitemsarea.one('span.draghome.choice' + choiceno); + }, + drag_item_homes : function() { + return dragitemsarea.all('span.draghome'); + }, + 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 Number(match[0]); + } + } + } + return null; + }, + inputs_for_choices : function () { + return topnode.all('input.choices'); + }, + input_for_choice : function (choiceno) { + return topnode.one('input.choice' + choiceno); + }, + marker_texts : function () { + return topnode.one('div.markertexts'); + } + }; + }, + + colours : ['#FFFFFF', '#B0C4DE', '#DCDCDC', '#D8BFD8', + '#87CEFA','#DAA520', '#FFD700', '#F0E68C'], + nextcolourindex : 0, + restart_colours : function () { + this.nextcolourindex = 0; + }, + get_next_colour : function () { + var colour = this.colours[this.nextcolourindex]; + this.nextcolourindex++; + if (this.nextcolourindex === this.colours.length) { + this.nextcolourindex = 0; + } + return colour; + }, + 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]; + }, + shapes : [], + draw_drop_zone : function (dropzoneno, markertext, shape, coords, colour, link) { + var existingmarkertext; + if (link) { + existingmarkertext = this.doc.marker_texts().one('span.markertext' + dropzoneno + ' a'); + } else { + existingmarkertext = this.doc.marker_texts().one('span.markertext' + dropzoneno); + } + + if (existingmarkertext) { + if (markertext !== '') { + existingmarkertext.setContent(markertext); + } else { + existingmarkertext.remove(true); + } + } else if (markertext !== '') { + var classnames = 'markertext markertext' + dropzoneno; + if (link) { + this.doc.marker_texts().append('' + + markertext + ''); + } else { + this.doc.marker_texts().append('' + + markertext + ''); + } + } + var drawfunc = 'draw_shape_' + shape; + if (this[drawfunc] instanceof Function){ + var xyfortext = this[drawfunc](dropzoneno, coords, colour); + if (xyfortext !== null) { + var markerspan = this.doc.top_node().one('div.ddarea div.markertexts span.markertext' + dropzoneno); + if (markerspan !== null) { + markerspan.setStyle('opacity', '0.6'); + xyfortext[0] -= markerspan.get('offsetWidth') / 2; + xyfortext[1] -= markerspan.get('offsetHeight') / 2; + markerspan.setXY(this.convert_to_window_xy(xyfortext)); + var markerspananchor = markerspan.one('a'); + if (markerspananchor !== null) { + markerspananchor.once('click', function (e, dropzoneno) { + var fill = this.shapes[dropzoneno].get('fill'); + fill.opacity = 1; + this.shapes[dropzoneno].set('fill', fill); + }, + this, + dropzoneno + ); + markerspananchor.set('tabIndex', 0); + } + } + } + } + }, + draw_shape_circle : function (dropzoneno, coords, colour) { + var coordsparts = coords.match(/(\d+),(\d+);(\d+)/); + if (coordsparts && coordsparts.length === 4) { + var xy = [Number(coordsparts[1]) - coordsparts[3], Number(coordsparts[2]) - coordsparts[3]]; + if (this.coords_in_img(xy)) { + var widthheight = [Number(coordsparts[3]) * 2, Number(coordsparts[3]) * 2]; + var shape = this.graphics.addShape({ + type: 'circle', + width: widthheight[0], + height: widthheight[1], + fill: { + color: colour, + opacity: "0.5" + }, + stroke: { + weight: 1, + color: "black" + } + }); + shape.setXY(this.convert_to_window_xy(xy)); + this.shapes[dropzoneno] = shape; + return [Number(coordsparts[1]), Number(coordsparts[2])]; + } + } + return null; + }, + draw_shape_rectangle : function (dropzoneno, coords, colour) { + var coordsparts = coords.match(/(\d+),(\d+);(\d+),(\d+)/); + if (coordsparts && coordsparts.length === 5) { + var xy = [Number(coordsparts[1]), Number(coordsparts[2])]; + var widthheight = [Number(coordsparts[3]), Number(coordsparts[4])]; + if (this.coords_in_img([xy[0] + widthheight[0], xy[1] + widthheight[1]])) { + var shape = this.graphics.addShape({ + type: 'rect', + width: widthheight[0], + height: widthheight[1], + fill: { + color: colour, + opacity: "0.5" + }, + stroke: { + weight: 1, + color: "black" + } + }); + shape.setXY(this.convert_to_window_xy(xy)); + this.shapes[dropzoneno] = shape; + return [Number(xy[0]) + widthheight[0] / 2, Number(xy[1]) + widthheight[1] / 2]; + } + } + return null; + + }, + draw_shape_polygon : function (dropzoneno, coords, colour) { + var coordsparts = coords.split(';'); + var xy = []; + for (var i in coordsparts) { + var parts = coordsparts[i].match(/^(\d+),(\d+)$/); + if (parts !== null && this.coords_in_img([parts[1], parts[2]])) { + xy[xy.length] = [parts[1], parts[2]]; + } + } + if (xy.length > 2) { + var polygon = this.graphics.addShape({ + type: "path", + stroke: { + weight: 1, + color: "black" + }, + fill: { + color: colour, + opacity : "0.5" + } + }); + var maxxy = [0,0]; + var minxy = [this.doc.bg_img().get('width'), this.doc.bg_img().get('height')]; + for (i = 0; i < xy.length; i++) { + //calculate min and max points to find center to show marker on + minxy[0] = Math.min(xy[i][0], minxy[0]); + minxy[1] = Math.min(xy[i][1], minxy[1]); + maxxy[0] = Math.max(xy[i][0], maxxy[0]); + maxxy[1] = Math.max(xy[i][1], maxxy[1]); + if (i === 0) { + polygon.moveTo(xy[i][0], xy[i][1]); + } else { + polygon.lineTo(xy[i][0], xy[i][1]); + } + } + if (Number(xy[0][0]) !== Number(xy[xy.length - 1][0]) || Number(xy[0][1]) !== Number(xy[xy.length - 1][1])) { + polygon.lineTo(xy[0][0], xy[0][1]); // Close polygon if not already closed. + } + polygon.end(); + polygon.setXY(this.doc.bg_img().getXY()); + this.shapes[dropzoneno] = polygon; + return [(minxy[0] + maxxy[0]) / 2, (minxy[1] + maxxy[1]) / 2]; + } + return null; + }, + coords_in_img : function (coords) { + return (coords[0] <= this.doc.bg_img().get('width') && + coords[1] <= this.doc.bg_img().get('height')); + } +}, { + NAME : DDMARKERDDNAME, + ATTRS : { + drops : {value : null}, + readonly : {value : false}, + topnode : {value : null} + } +}); +M.qtype_ddmarker = M.qtype_ddmarker || {}; +M.qtype_ddmarker.dd_base_class = DDMARKER_DD; + +var DDMARKERQUESTIONNAME = 'ddmarker_question'; +var DDMARKER_QUESTION = function() { + DDMARKER_QUESTION.superclass.constructor.apply(this, arguments); +}; +/** + * This is the code for question rendering. + */ +Y.extend(DDMARKER_QUESTION, M.qtype_ddmarker.dd_base_class, { + initializer : function() { + this.doc = this.doc_structure(this); + this.poll_for_image_load(null, false, 0, this.after_image_load); + this.doc.bg_img().after('load', this.poll_for_image_load, this, + false, 0, this.after_image_load); + }, + after_image_load : function () { + this.redraw_drags_and_drops(); + Y.later(2000, this, this.redraw_drags_and_drops, [], true); + }, + clone_new_drag_item : function (draghome, itemno) { + var drag = draghome.cloneNode(true); + drag.removeClass('draghome'); + drag.addClass('dragitem'); + drag.addClass('item' + itemno); + drag.one('span.markertext').setStyle('opacity', 0.6); + draghome.insert(drag, 'after'); + if (!this.get('readonly')) { + this.draggable(drag); + } + return drag; + }, + draggable : function (drag) { + var dd = new Y.DD.Drag({ + node: drag, + dragMode: 'intersect' + }).plug(Y.Plugin.DDConstrained, {constrain2node: this.doc.top_node()}); + dd.after('drag:start', function(e){ + var dragnode = e.target.get('node'); + dragnode.addClass('beingdragged'); + var choiceno = this.get_choiceno_for_node(dragnode); + var itemno = this.get_itemno_for_node(dragnode); + if (itemno !== null) { + dragnode.removeClass('item' + dragnode); + } + this.save_all_xy_for_choice(choiceno, null); + this.redraw_drags_and_drops(); + }, this); + dd.after('drag:end', function(e) { + var dragnode = e.target.get('node'); + dragnode.removeClass('beingdragged'); + var choiceno = this.get_choiceno_for_node(dragnode); + this.save_all_xy_for_choice(choiceno, dragnode); + this.redraw_drags_and_drops(); + }, this); + //--- keyboard accessibility + drag.set('tabIndex', 0); + drag.on('dragchange', this.drop_zone_key_press, this); + }, + save_all_xy_for_choice: function (choiceno, dropped) { + var coords = []; + var bgimgxy; + for (var i = 0; i <= this.doc.drag_items_for_choice(choiceno).size(); i++) { + var dragitem = this.doc.drag_item_for_choice(choiceno, i); + if (dragitem) { + dragitem.removeClass('item' + i); + if (!dragitem.hasClass('beingdragged')) { + bgimgxy = this.convert_to_bg_img_xy(dragitem.getXY()); + if (this.xy_in_bgimg(bgimgxy)) { + dragitem.removeClass('item' + i); + dragitem.addClass('item' + coords.length); + coords[coords.length] = bgimgxy; + } + } + } + } + if (dropped !== null){ + bgimgxy = this.convert_to_bg_img_xy(dropped.getXY()); + dropped.addClass('item' + coords.length); + if (this.xy_in_bgimg(bgimgxy)) { + coords[coords.length] = bgimgxy; + } + } + this.set_form_value(choiceno, coords.join(';')); + }, + reset_drag_xy : function (choiceno) { + this.set_form_value(choiceno, ''); + }, + set_form_value : function (choiceno, value) { + this.doc.input_for_choice(choiceno).set('value', value); + }, + //make sure xy value is not out of bounds of bg image + xy_in_bgimg : function (bgimgxy) { + if ((bgimgxy[0] < 0) || + (bgimgxy[1] < 0) || + (bgimgxy[0] > this.doc.bg_img().get('width')) || + (bgimgxy[1] > this.doc.bg_img().get('height'))){ + return false; + } else { + return true; + } + }, + constrain_to_bgimg : function (windowxy) { + var bgimgxy = this.convert_to_bg_img_xy(windowxy); + bgimgxy[0] = Math.max(0, bgimgxy[0]); + bgimgxy[1] = Math.max(0, bgimgxy[1]); + bgimgxy[0] = Math.min(this.doc.bg_img().get('width'), bgimgxy[0]); + bgimgxy[1] = Math.min(this.doc.bg_img().get('height'), bgimgxy[1]); + return this.convert_to_window_xy(bgimgxy); + }, + 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]; + }, + redraw_drags_and_drops : function() { + this.doc.drag_items().each(function(item) { + //if (!item.hasClass('beingdragged')){ + item.addClass('unneeded'); + //} + }, this); + this.doc.inputs_for_choices().each(function (input) { + var choiceno = this.get_choiceno_for_node(input); + var coords = this.get_coords(input); + var dragitemhome = this.doc.drag_item_home(choiceno); + for (var i = 0; i < coords.length; i++) { + var dragitem = this.doc.drag_item_for_choice(choiceno, i); + if (!dragitem || dragitem.hasClass('beingdragged')) { + dragitem = this.clone_new_drag_item(dragitemhome, i); + } else { + dragitem.removeClass('unneeded'); + } + dragitem.setXY(coords[i]); + } + }, this); + this.doc.drag_items().each(function(item) { + if (item.hasClass('unneeded') && !item.hasClass('beingdragged')) { + item.remove(true); + } + }, this); + if (this.graphics !== null) { + this.graphics.clear(); + } else { + this.graphics = new Y.Graphic( + {render:this.doc.top_node().one("div.ddarea div.dropzones")} + ); + } + if (this.get('dropzones').length !== 0) { + this.restart_colours(); + for (var dropzoneno in this.get('dropzones')) { + var colourfordropzone = this.get_next_colour(); + var d = this.get('dropzones')[dropzoneno]; + this.draw_drop_zone(dropzoneno, d.markertext, + d.shape, d.coords, colourfordropzone, true); + } + } + }, + /** + * Determine what drag items need to be shown and + * return coords of all drag items except any that are currently being dragged + * based on contents of hidden inputs and whether drags are 'infinite' or how many drags should be shown. + */ + get_coords : function (input) { + var choiceno = this.get_choiceno_for_node(input); + var fv = input.get('value'); + var infinite = input.hasClass('infinite'); + var noofdrags = this.get_noofdrags_for_node(input); + var dragging = (null !== this.doc.drag_item_being_dragged(choiceno)); + var coords = []; + if (fv !== '') { + var coordsstrings = fv.split(';'); + for (var i = 0; i < coordsstrings.length; i++) { + coords[coords.length] = this.convert_to_window_xy(coordsstrings[i].split(',')); + } + } + var displayeddrags = coords.length + (dragging ? 1 : 0); + if (infinite || (displayeddrags < noofdrags)) { + coords[coords.length] = this.drag_home_xy(choiceno); + } + return coords; + }, + drag_home_xy : function (choiceno) { + var dragitemhome = this.doc.drag_item_home(choiceno); + return [dragitemhome.getX(), dragitemhome.getY() - 12]; + }, + get_choiceno_for_node : function(node) { + return Number(this.doc.get_classname_numeric_suffix(node, 'choice')); + }, + get_itemno_for_node : function(node) { + return Number(this.doc.get_classname_numeric_suffix(node, 'item')); + }, + get_noofdrags_for_node : function(node) { + return Number(this.doc.get_classname_numeric_suffix(node, 'noofdrags')); + }, + + // Keyboard accessibility stuff below here. + drop_zone_key_press : function (e) { + var dragitem = e.target; + var xy = dragitem.getXY(); + switch (e.direction) { + case 'left' : + xy[0] -= 1; + break; + case 'right' : + xy[0] += 1; + break; + case 'down' : + xy[1] += 1; + break; + case 'up' : + xy[1] -= 1; + break; + case 'remove' : + xy = null; + break; + } + var choiceno = this.get_choiceno_for_node(dragitem); + if (xy !== null) { + xy = this.constrain_to_bgimg(xy); + } else { + xy = this.drag_home_xy(choiceno); + } + e.preventDefault(); + dragitem.setXY(xy); + this.save_all_xy_for_choice(choiceno, null); + } +}, {NAME : DDMARKERQUESTIONNAME, ATTRS : {dropzones:{value:[]}}}); + +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': 'remove', // Space + '37': 'left', // Left arrow + '38': 'up', // Up arrow + '39': 'right', // Right arrow + '40': 'down', // Down arrow + '65': 'left', // a + '87': 'up', // w + '68': 'right', // d + '83': 'down', // s + '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_ddmarker.init_question = function(config) { + return new DDMARKER_QUESTION(config); +}; + + +}, '@VERSION@', {"requires": ["node", "event-resize", "dd", "dd-drop", "dd-constrain", "graphics"]}); diff --git a/question/type/ddmarker/yui/build/moodle-qtype_ddmarker-dd/moodle-qtype_ddmarker-dd-min.js b/question/type/ddmarker/yui/build/moodle-qtype_ddmarker-dd/moodle-qtype_ddmarker-dd-min.js new file mode 100644 index 00000000000..40ef3f541c1 --- /dev/null +++ b/question/type/ddmarker/yui/build/moodle-qtype_ddmarker-dd/moodle-qtype_ddmarker-dd-min.js @@ -0,0 +1,2 @@ +YUI.add("moodle-qtype_ddmarker-dd",function(e,t){var n="moodle-qtype_ddmarker-dd",r=function(){r.superclass.constructor.apply(this,arguments)};e.extend(r,e.Base,{doc:null,polltimer:null,afterimageloaddone:!1,graphics:null,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"));if(s)this.polltimer!==null&&(this.polltimer.cancel(),this.polltimer=null),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 o=[null,n,r,i];this.polltimer=e.later(1e3,this,this.poll_for_image_load,o,!0)}},doc_structure:function(){var t=e.one(this.get("topnode")),n=t.one("div.dragitems"),r=t.one("div.droparea");return{top_node:function(){return t},bg_img:function(){return t.one(".dropbackground")},load_bg_img:function(e){r.setContent(''),this.bg_img().on("load",this.on_image_load,this,"bg_image")},drag_items:function(){return n.all(".dragitem")},drag_items_for_choice:function(e){return n.all("span.dragitem.choice"+e)},drag_item_for_choice:function(e,t){return n.one("span.dragitem.choice"+e+".item"+t)},drag_item_being_dragged:function(e){return n.one("span.dragitem.beingdragged.choice"+e)},drag_item_home:function(e){return n.one("span.draghome.choice"+e)},drag_item_homes:function(){return n.all("span.draghome")},get_classname_numeric_suffix:function(e,t){var n=e.getAttribute("class");if(n!==""){var r=n.split(" ");for(var i=0;i'+t+""):this.doc.marker_texts().append(''+t+"")}var a="draw_shape_"+n;if(this[a]instanceof Function){var f=this[a](e,r,i);if(f!==null){var l=this.doc.top_node().one("div.ddarea div.markertexts span.markertext"+e);if(l!==null){l.setStyle("opacity","0.6"),f[0]-=l.get("offsetWidth")/2,f[1]-=l.get("offsetHeight")/2,l.setXY(this.convert_to_window_xy(f));var c=l.one("a");c!==null&&(c.once("click",function(e,t){var n=this.shapes[t].get("fill");n.opacity=1,this.shapes[t].set("fill",n)},this,e),c.set("tabIndex",0))}}}},draw_shape_circle:function(e,t,n){var r=t.match(/(\d+),(\d+);(\d+)/);if(r&&r.length===4){var i=[Number(r[1])-r[3],Number(r[2])-r[3]];if(this.coords_in_img(i)){var s=[Number(r[3])*2,Number(r[3])*2],o=this.graphics.addShape({type:"circle",width:s[0],height:s[1],fill:{color:n,opacity:"0.5"},stroke:{weight:1,color:"black"}});return o.setXY(this.convert_to_window_xy(i)),this.shapes[e]=o,[Number(r[1]),Number(r[2])]}}return null},draw_shape_rectangle:function(e,t,n){var r=t.match(/(\d+),(\d+);(\d+),(\d+)/);if(r&&r.length===5){var i=[Number(r[1]),Number(r[2])],s=[Number(r[3]),Number(r[4])];if(this.coords_in_img([i[0]+s[0],i[1]+s[1]])){var o=this.graphics.addShape({type:"rect",width:s[0],height:s[1],fill:{color:n,opacity:"0.5"},stroke:{weight:1,color:"black"}});return o.setXY(this.convert_to_window_xy(i)),this.shapes[e]=o,[Number(i[0])+s[0]/2,Number(i[1])+s[1]/2]}}return null},draw_shape_polygon:function(e,t,n){var r=t.split(";"),i=[];for(var s in r){var o=r[s].match(/^(\d+),(\d+)$/);o!==null&&this.coords_in_img([o[1],o[2]])&&(i[i.length]=[o[1],o[2]])}if(i.length>2){var u=this.graphics.addShape({type:"path",stroke:{weight:1,color:"black"},fill:{color:n,opacity:"0.5"}}),a=[0,0],f=[this.doc.bg_img().get("width"),this.doc.bg_img().get("height")];for(s=0;sthis.doc.bg_img().get("width")||e[1]>this.doc.bg_img().get("height")?!1:!0},constrain_to_bgimg:function(e){var t=this.convert_to_bg_img_xy(e);return t[0]=Math.max(0,t[0]),t[1]=Math.max(0,t[1]),t[0]=Math.min(this.doc.bg_img().get("width"),t[0]),t[1]=Math.min(this.doc.bg_img().get("height"),t[1]),this.convert_to_window_xy(t)},convert_to_bg_img_xy:function(e){return[Number(e[0])-this.doc.bg_img().getX()-1,Number(e[1])-this.doc.bg_img().getY()-1]},redraw_drags_and_drops:function(){this.doc.drag_items().each(function(e){e.addClass("unneeded")},this),this.doc.inputs_for_choices().each(function(e){var t=this.get_choiceno_for_node(e),n=this.get_coords(e),r=this.doc.drag_item_home(t);for(var i=0;i. + +var DDMARKERDDNAME = 'moodle-qtype_ddmarker-dd'; +var DDMARKER_DD = function() { + DDMARKER_DD.superclass.constructor.apply(this, arguments); +}; +/** + * This is the base class for the question rendering and question editing form code. + */ +Y.extend(DDMARKER_DD, Y.Base, { + doc : null, + polltimer : null, + afterimageloaddone : false, + graphics : null, + 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'); + } + if (bgdone) { + if (this.polltimer !== null) { + this.polltimer.cancel(); + this.polltimer = null; + } + 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 () { + 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; + }, + 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'); + }, + drag_items : function() { + return dragitemsarea.all('.dragitem'); + }, + drag_items_for_choice : function(choiceno) { + return dragitemsarea.all('span.dragitem.choice' + choiceno); + }, + drag_item_for_choice : function(choiceno, itemno) { + return dragitemsarea.one('span.dragitem.choice' + choiceno + + '.item' + itemno); + }, + drag_item_being_dragged : function(choiceno) { + return dragitemsarea.one('span.dragitem.beingdragged.choice' + choiceno); + }, + drag_item_home : function (choiceno) { + return dragitemsarea.one('span.draghome.choice' + choiceno); + }, + drag_item_homes : function() { + return dragitemsarea.all('span.draghome'); + }, + 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 Number(match[0]); + } + } + } + return null; + }, + inputs_for_choices : function () { + return topnode.all('input.choices'); + }, + input_for_choice : function (choiceno) { + return topnode.one('input.choice' + choiceno); + }, + marker_texts : function () { + return topnode.one('div.markertexts'); + } + }; + }, + + colours : ['#FFFFFF', '#B0C4DE', '#DCDCDC', '#D8BFD8', + '#87CEFA','#DAA520', '#FFD700', '#F0E68C'], + nextcolourindex : 0, + restart_colours : function () { + this.nextcolourindex = 0; + }, + get_next_colour : function () { + var colour = this.colours[this.nextcolourindex]; + this.nextcolourindex++; + if (this.nextcolourindex === this.colours.length) { + this.nextcolourindex = 0; + } + return colour; + }, + 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]; + }, + shapes : [], + draw_drop_zone : function (dropzoneno, markertext, shape, coords, colour, link) { + var existingmarkertext; + if (link) { + existingmarkertext = this.doc.marker_texts().one('span.markertext' + dropzoneno + ' a'); + } else { + existingmarkertext = this.doc.marker_texts().one('span.markertext' + dropzoneno); + } + + if (existingmarkertext) { + if (markertext !== '') { + existingmarkertext.setContent(markertext); + } else { + existingmarkertext.remove(true); + } + } else if (markertext !== '') { + var classnames = 'markertext markertext' + dropzoneno; + if (link) { + this.doc.marker_texts().append('' + + markertext + ''); + } else { + this.doc.marker_texts().append('' + + markertext + ''); + } + } + var drawfunc = 'draw_shape_' + shape; + if (this[drawfunc] instanceof Function){ + var xyfortext = this[drawfunc](dropzoneno, coords, colour); + if (xyfortext !== null) { + var markerspan = this.doc.top_node().one('div.ddarea div.markertexts span.markertext' + dropzoneno); + if (markerspan !== null) { + markerspan.setStyle('opacity', '0.6'); + xyfortext[0] -= markerspan.get('offsetWidth') / 2; + xyfortext[1] -= markerspan.get('offsetHeight') / 2; + markerspan.setXY(this.convert_to_window_xy(xyfortext)); + var markerspananchor = markerspan.one('a'); + if (markerspananchor !== null) { + markerspananchor.once('click', function (e, dropzoneno) { + var fill = this.shapes[dropzoneno].get('fill'); + fill.opacity = 1; + this.shapes[dropzoneno].set('fill', fill); + }, + this, + dropzoneno + ); + markerspananchor.set('tabIndex', 0); + } + } + } + } + }, + draw_shape_circle : function (dropzoneno, coords, colour) { + var coordsparts = coords.match(/(\d+),(\d+);(\d+)/); + if (coordsparts && coordsparts.length === 4) { + var xy = [Number(coordsparts[1]) - coordsparts[3], Number(coordsparts[2]) - coordsparts[3]]; + if (this.coords_in_img(xy)) { + var widthheight = [Number(coordsparts[3]) * 2, Number(coordsparts[3]) * 2]; + var shape = this.graphics.addShape({ + type: 'circle', + width: widthheight[0], + height: widthheight[1], + fill: { + color: colour, + opacity: "0.5" + }, + stroke: { + weight: 1, + color: "black" + } + }); + shape.setXY(this.convert_to_window_xy(xy)); + this.shapes[dropzoneno] = shape; + return [Number(coordsparts[1]), Number(coordsparts[2])]; + } + } + return null; + }, + draw_shape_rectangle : function (dropzoneno, coords, colour) { + var coordsparts = coords.match(/(\d+),(\d+);(\d+),(\d+)/); + if (coordsparts && coordsparts.length === 5) { + var xy = [Number(coordsparts[1]), Number(coordsparts[2])]; + var widthheight = [Number(coordsparts[3]), Number(coordsparts[4])]; + if (this.coords_in_img([xy[0] + widthheight[0], xy[1] + widthheight[1]])) { + var shape = this.graphics.addShape({ + type: 'rect', + width: widthheight[0], + height: widthheight[1], + fill: { + color: colour, + opacity: "0.5" + }, + stroke: { + weight: 1, + color: "black" + } + }); + shape.setXY(this.convert_to_window_xy(xy)); + this.shapes[dropzoneno] = shape; + return [Number(xy[0]) + widthheight[0] / 2, Number(xy[1]) + widthheight[1] / 2]; + } + } + return null; + + }, + draw_shape_polygon : function (dropzoneno, coords, colour) { + var coordsparts = coords.split(';'); + var xy = []; + for (var i in coordsparts) { + var parts = coordsparts[i].match(/^(\d+),(\d+)$/); + if (parts !== null && this.coords_in_img([parts[1], parts[2]])) { + xy[xy.length] = [parts[1], parts[2]]; + } + } + if (xy.length > 2) { + var polygon = this.graphics.addShape({ + type: "path", + stroke: { + weight: 1, + color: "black" + }, + fill: { + color: colour, + opacity : "0.5" + } + }); + var maxxy = [0,0]; + var minxy = [this.doc.bg_img().get('width'), this.doc.bg_img().get('height')]; + for (i = 0; i < xy.length; i++) { + //calculate min and max points to find center to show marker on + minxy[0] = Math.min(xy[i][0], minxy[0]); + minxy[1] = Math.min(xy[i][1], minxy[1]); + maxxy[0] = Math.max(xy[i][0], maxxy[0]); + maxxy[1] = Math.max(xy[i][1], maxxy[1]); + if (i === 0) { + polygon.moveTo(xy[i][0], xy[i][1]); + } else { + polygon.lineTo(xy[i][0], xy[i][1]); + } + } + if (Number(xy[0][0]) !== Number(xy[xy.length - 1][0]) || Number(xy[0][1]) !== Number(xy[xy.length - 1][1])) { + polygon.lineTo(xy[0][0], xy[0][1]); // Close polygon if not already closed. + } + polygon.end(); + polygon.setXY(this.doc.bg_img().getXY()); + this.shapes[dropzoneno] = polygon; + return [(minxy[0] + maxxy[0]) / 2, (minxy[1] + maxxy[1]) / 2]; + } + return null; + }, + coords_in_img : function (coords) { + return (coords[0] <= this.doc.bg_img().get('width') && + coords[1] <= this.doc.bg_img().get('height')); + } +}, { + NAME : DDMARKERDDNAME, + ATTRS : { + drops : {value : null}, + readonly : {value : false}, + topnode : {value : null} + } +}); +M.qtype_ddmarker = M.qtype_ddmarker || {}; +M.qtype_ddmarker.dd_base_class = DDMARKER_DD; + +var DDMARKERQUESTIONNAME = 'ddmarker_question'; +var DDMARKER_QUESTION = function() { + DDMARKER_QUESTION.superclass.constructor.apply(this, arguments); +}; +/** + * This is the code for question rendering. + */ +Y.extend(DDMARKER_QUESTION, M.qtype_ddmarker.dd_base_class, { + initializer : function() { + this.doc = this.doc_structure(this); + this.poll_for_image_load(null, false, 0, this.after_image_load); + this.doc.bg_img().after('load', this.poll_for_image_load, this, + false, 0, this.after_image_load); + }, + after_image_load : function () { + this.redraw_drags_and_drops(); + Y.later(2000, this, this.redraw_drags_and_drops, [], true); + }, + clone_new_drag_item : function (draghome, itemno) { + var drag = draghome.cloneNode(true); + drag.removeClass('draghome'); + drag.addClass('dragitem'); + drag.addClass('item' + itemno); + drag.one('span.markertext').setStyle('opacity', 0.6); + draghome.insert(drag, 'after'); + if (!this.get('readonly')) { + this.draggable(drag); + } + return drag; + }, + draggable : function (drag) { + var dd = new Y.DD.Drag({ + node: drag, + dragMode: 'intersect' + }).plug(Y.Plugin.DDConstrained, {constrain2node: this.doc.top_node()}); + dd.after('drag:start', function(e){ + var dragnode = e.target.get('node'); + dragnode.addClass('beingdragged'); + var choiceno = this.get_choiceno_for_node(dragnode); + var itemno = this.get_itemno_for_node(dragnode); + if (itemno !== null) { + dragnode.removeClass('item' + dragnode); + } + this.save_all_xy_for_choice(choiceno, null); + this.redraw_drags_and_drops(); + }, this); + dd.after('drag:end', function(e) { + var dragnode = e.target.get('node'); + dragnode.removeClass('beingdragged'); + var choiceno = this.get_choiceno_for_node(dragnode); + this.save_all_xy_for_choice(choiceno, dragnode); + this.redraw_drags_and_drops(); + }, this); + //--- keyboard accessibility + drag.set('tabIndex', 0); + drag.on('dragchange', this.drop_zone_key_press, this); + }, + save_all_xy_for_choice: function (choiceno, dropped) { + var coords = []; + var bgimgxy; + for (var i = 0; i <= this.doc.drag_items_for_choice(choiceno).size(); i++) { + var dragitem = this.doc.drag_item_for_choice(choiceno, i); + if (dragitem) { + dragitem.removeClass('item' + i); + if (!dragitem.hasClass('beingdragged')) { + bgimgxy = this.convert_to_bg_img_xy(dragitem.getXY()); + if (this.xy_in_bgimg(bgimgxy)) { + dragitem.removeClass('item' + i); + dragitem.addClass('item' + coords.length); + coords[coords.length] = bgimgxy; + } + } + } + } + if (dropped !== null){ + bgimgxy = this.convert_to_bg_img_xy(dropped.getXY()); + dropped.addClass('item' + coords.length); + if (this.xy_in_bgimg(bgimgxy)) { + coords[coords.length] = bgimgxy; + } + } + this.set_form_value(choiceno, coords.join(';')); + }, + reset_drag_xy : function (choiceno) { + this.set_form_value(choiceno, ''); + }, + set_form_value : function (choiceno, value) { + this.doc.input_for_choice(choiceno).set('value', value); + }, + //make sure xy value is not out of bounds of bg image + xy_in_bgimg : function (bgimgxy) { + if ((bgimgxy[0] < 0) || + (bgimgxy[1] < 0) || + (bgimgxy[0] > this.doc.bg_img().get('width')) || + (bgimgxy[1] > this.doc.bg_img().get('height'))){ + return false; + } else { + return true; + } + }, + constrain_to_bgimg : function (windowxy) { + var bgimgxy = this.convert_to_bg_img_xy(windowxy); + bgimgxy[0] = Math.max(0, bgimgxy[0]); + bgimgxy[1] = Math.max(0, bgimgxy[1]); + bgimgxy[0] = Math.min(this.doc.bg_img().get('width'), bgimgxy[0]); + bgimgxy[1] = Math.min(this.doc.bg_img().get('height'), bgimgxy[1]); + return this.convert_to_window_xy(bgimgxy); + }, + 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]; + }, + redraw_drags_and_drops : function() { + this.doc.drag_items().each(function(item) { + //if (!item.hasClass('beingdragged')){ + item.addClass('unneeded'); + //} + }, this); + this.doc.inputs_for_choices().each(function (input) { + var choiceno = this.get_choiceno_for_node(input); + var coords = this.get_coords(input); + var dragitemhome = this.doc.drag_item_home(choiceno); + for (var i = 0; i < coords.length; i++) { + var dragitem = this.doc.drag_item_for_choice(choiceno, i); + if (!dragitem || dragitem.hasClass('beingdragged')) { + dragitem = this.clone_new_drag_item(dragitemhome, i); + } else { + dragitem.removeClass('unneeded'); + } + dragitem.setXY(coords[i]); + } + }, this); + this.doc.drag_items().each(function(item) { + if (item.hasClass('unneeded') && !item.hasClass('beingdragged')) { + item.remove(true); + } + }, this); + if (this.graphics !== null) { + this.graphics.clear(); + } else { + this.graphics = new Y.Graphic( + {render:this.doc.top_node().one("div.ddarea div.dropzones")} + ); + } + if (this.get('dropzones').length !== 0) { + this.restart_colours(); + for (var dropzoneno in this.get('dropzones')) { + var colourfordropzone = this.get_next_colour(); + var d = this.get('dropzones')[dropzoneno]; + this.draw_drop_zone(dropzoneno, d.markertext, + d.shape, d.coords, colourfordropzone, true); + } + } + }, + /** + * Determine what drag items need to be shown and + * return coords of all drag items except any that are currently being dragged + * based on contents of hidden inputs and whether drags are 'infinite' or how many drags should be shown. + */ + get_coords : function (input) { + var choiceno = this.get_choiceno_for_node(input); + var fv = input.get('value'); + var infinite = input.hasClass('infinite'); + var noofdrags = this.get_noofdrags_for_node(input); + var dragging = (null !== this.doc.drag_item_being_dragged(choiceno)); + var coords = []; + if (fv !== '') { + var coordsstrings = fv.split(';'); + for (var i = 0; i < coordsstrings.length; i++) { + coords[coords.length] = this.convert_to_window_xy(coordsstrings[i].split(',')); + } + } + var displayeddrags = coords.length + (dragging ? 1 : 0); + if (infinite || (displayeddrags < noofdrags)) { + coords[coords.length] = this.drag_home_xy(choiceno); + } + return coords; + }, + drag_home_xy : function (choiceno) { + var dragitemhome = this.doc.drag_item_home(choiceno); + return [dragitemhome.getX(), dragitemhome.getY() - 12]; + }, + get_choiceno_for_node : function(node) { + return Number(this.doc.get_classname_numeric_suffix(node, 'choice')); + }, + get_itemno_for_node : function(node) { + return Number(this.doc.get_classname_numeric_suffix(node, 'item')); + }, + get_noofdrags_for_node : function(node) { + return Number(this.doc.get_classname_numeric_suffix(node, 'noofdrags')); + }, + + // Keyboard accessibility stuff below here. + drop_zone_key_press : function (e) { + var dragitem = e.target; + var xy = dragitem.getXY(); + switch (e.direction) { + case 'left' : + xy[0] -= 1; + break; + case 'right' : + xy[0] += 1; + break; + case 'down' : + xy[1] += 1; + break; + case 'up' : + xy[1] -= 1; + break; + case 'remove' : + xy = null; + break; + } + var choiceno = this.get_choiceno_for_node(dragitem); + if (xy !== null) { + xy = this.constrain_to_bgimg(xy); + } else { + xy = this.drag_home_xy(choiceno); + } + e.preventDefault(); + dragitem.setXY(xy); + this.save_all_xy_for_choice(choiceno, null); + } +}, {NAME : DDMARKERQUESTIONNAME, ATTRS : {dropzones:{value:[]}}}); + +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': 'remove', // Space + '37': 'left', // Left arrow + '38': 'up', // Up arrow + '39': 'right', // Right arrow + '40': 'down', // Down arrow + '65': 'left', // a + '87': 'up', // w + '68': 'right', // d + '83': 'down', // s + '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_ddmarker.init_question = function(config) { + return new DDMARKER_QUESTION(config); +}; + + +}, '@VERSION@', {"requires": ["node", "event-resize", "dd", "dd-drop", "dd-constrain", "graphics"]}); diff --git a/question/type/ddmarker/yui/build/moodle-qtype_ddmarker-form/moodle-qtype_ddmarker-form-debug.js b/question/type/ddmarker/yui/build/moodle-qtype_ddmarker-form/moodle-qtype_ddmarker-form-debug.js new file mode 100644 index 00000000000..cccbc22909f --- /dev/null +++ b/question/type/ddmarker/yui/build/moodle-qtype_ddmarker-form/moodle-qtype_ddmarker-form-debug.js @@ -0,0 +1,272 @@ +YUI.add('moodle-qtype_ddmarker-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 DDMARKERFORMNAME = 'moodle-qtype_ddmarker-form'; +var DDMARKER_FORM = function() { + DDMARKER_FORM.superclass.constructor.apply(this, arguments); +}; +Y.extend(DDMARKER_FORM, M.qtype_ddmarker.dd_base_class, { + fp : null, + + initializer : function() { + this.fp = this.file_pickers(); + var tn = Y.one(this.get('topnode')); + tn.one('div.fcontainer').append( + '
' + + '
' + + '
' + + '
' + + '
' + + '
'); + this.doc = this.doc_structure(this); + this.stop_selector_events(); + this.set_options_for_drag_item_selectors(); + this.setup_form_events(); + Y.later(500, this, this.update_drop_zones, [], true); + Y.after(this.load_bg_image, M.form_filepicker, 'callback', this); + this.load_bg_image(); + }, + + load_bg_image : function() { + var bgimageurl = this.fp.file('bgimage').href; + if (bgimageurl !== null) { + this.doc.load_bg_img(bgimageurl); + + 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); + } + }, + + constrain_image_size : function (e) { + var maxsize = this.get('maxsizes').bgimage; + 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); + }, + + update_drop_zones : function () { + + // Set up drop zones. + if (this.graphics !== null) { + this.graphics.destroy(); + } + this.restart_colours(); + this.graphics = new Y.Graphic({render:"div.ddarea div.dropzones"}); + var noofdropzones = this.form.get_form_value('nodropzone', []); + for (var dropzoneno = 0; dropzoneno < noofdropzones; dropzoneno++) { + var dragitemno = this.form.get_form_value('drops', [dropzoneno, 'choice']); + var markertext = this.get_marker_text(dragitemno); + var shape = this.form.get_form_value('drops', [dropzoneno, 'shape']); + var coords = this.get_coords(dropzoneno); + var colourfordropzone = this.get_next_colour(); + Y.one('input#id_drops_' + dropzoneno + '_coords') + .setStyle('background-color', colourfordropzone); + this.draw_drop_zone(dropzoneno, markertext, + shape, coords, colourfordropzone, false); + } + Y.one('div.ddarea .grid') + .setXY(this.doc.bg_img().getXY()) + .setStyle('width', this.doc.bg_img().get('width')) + .setStyle('height', this.doc.bg_img().get('height')); + }, + + get_coords : function (dropzoneno) { + var coords = this.form.get_form_value('drops', [dropzoneno, 'coords']); + return coords.replace(new RegExp("\\s*", 'g'), ''); + }, + get_marker_text : function (markerno) { + if (Number(markerno) !== 0) { + var label = this.form.get_form_value('drags', [markerno - 1, 'label']); + return label.replace(new RegExp("^\\s*(.*)\\s*$"), "$1"); + } else { + return ''; + } + }, + set_options_for_drag_item_selectors : function () { + var dragitemsoptions = {0: ''}; + for (var i = 1; i <= this.form.get_form_value('noitems', []); i++) { + var label = this.get_marker_text(i); + if (label !== "") { + dragitemsoptions[i] = Y.Escape.html(label); + } + } + // Get all the currently selected drags for each drop. + var selectedvalues = []; + var selector; + for (i = 0; i < this.form.get_form_value('nodropzone', []); i++) { + selector = Y.one('#id_drops_' + i + '_choice'); + selectedvalues[i] = Number(selector.get('value')); + } + for (i = 0; i < this.form.get_form_value('nodropzone', []); i++) { + selector = Y.one('#id_drops_' + i + '_choice'); + // Remove all options for drag choice. + selector.all('option').remove(true); + // And recreate the options. + for (var value in dragitemsoptions) { + value = Number(value); + var option = ''; + selector.append(option); + var optionnode = selector.one('option[value="' + value + '"]'); + // Is this the currently selected value? + if (value === selectedvalues[i]) { + optionnode.set('selected', true); + } else { + // It is not the currently selected value, is it selectable? + if (value !== 0) { // The 'no item' option is always selectable. + // Variables to hold form values about this drag item. + var noofdrags = this.form.get_form_value('drags', [value - 1, 'noofdrags']); + if (Number(noofdrags) !== 0) { // 'noofdrags == 0' means infinite. + // Go through all selected values in drop downs. + for (var k in selectedvalues) { + // Count down 'noofdrags' and if reach zero then set disabled option for this drag item. + if (Number(selectedvalues[k]) === value) { + if (Number(noofdrags) === 1) { + optionnode.set('disabled', true); + break; + } else { + noofdrags--; + } + } + } + } + } + } + } + } + }, + + stop_selector_events : function () { + Y.all('fieldset#id_dropzoneheader select').detachAll(); + }, + + setup_form_events : function () { + //events triggered by changes to form data + + // Changes to labels. + Y.all('fieldset#id_draggableitemheader input').on('change', function () { + this.set_options_for_drag_item_selectors(); + }, this); + + // Changes to selected drag item. + Y.all('fieldset#id_draggableitemheader select').on('change', function () { + this.set_options_for_drag_item_selectors(); + }, this); + + // Change in selected item. + Y.all('fieldset#id_dropzoneheader select').on('change', function () { + this.set_options_for_drag_item_selectors(); + }, this); + }, + + /** + * 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 : DDMARKERFORMNAME, ATTRS : {maxsizes:{value:null}}}); + +M.qtype_ddmarker = M.qtype_ddmarker || {}; +M.qtype_ddmarker.init_form = function(config) { + return new DDMARKER_FORM(config); +}; + + +}, '@VERSION@', {"requires": ["moodle-qtype_ddmarker-dd", "form_filepicker", "graphics", "escape"]}); diff --git a/question/type/ddmarker/yui/build/moodle-qtype_ddmarker-form/moodle-qtype_ddmarker-form-min.js b/question/type/ddmarker/yui/build/moodle-qtype_ddmarker-form/moodle-qtype_ddmarker-form-min.js new file mode 100644 index 00000000000..0c20abff8b8 --- /dev/null +++ b/question/type/ddmarker/yui/build/moodle-qtype_ddmarker-form/moodle-qtype_ddmarker-form-min.js @@ -0,0 +1 @@ +YUI.add("moodle-qtype_ddmarker-form",function(e,t){var n="moodle-qtype_ddmarker-form",r=function(){r.superclass.constructor.apply(this,arguments)};e.extend(r,M.qtype_ddmarker.dd_base_class,{fp:null,initializer:function(){this.fp=this.file_pickers();var t=e.one(this.get("topnode"));t.one("div.fcontainer").append('
'),this.doc=this.doc_structure(this),this.stop_selector_events(),this.set_options_for_drag_item_selectors(),this.setup_form_events(),e.later(500,this,this.update_drop_zones,[],!0),e.after(this.load_bg_image,M.form_filepicker,"callback",this),this.load_bg_image()},load_bg_image:function(){var t=this.fp.file("bgimage").href;if(t!==null){this.doc.load_bg_img(t);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)}},constrain_image_size:function(e){var t=this.get("maxsizes").bgimage,n=Math.max(e.target.get("width")/t.width,e.target.get("height")/t.height);n>1&&e.target.set("width",Math.floor(e.target.get("width")/n)),e.target.addClass("constrained"),e.target.detach("load",this.constrain_image_size)},update_drop_zones:function(){this.graphics!==null&&this.graphics.destroy(),this.restart_colours(),this.graphics=new e.Graphic({render:"div.ddarea div.dropzones"});var t=this.form.get_form_value("nodropzone",[]);for(var n=0;n'+t[o]+"";s.append(u);var a=s.one('option[value="'+o+'"]');if(o===i[n])a.set("selected",!0);else if(o!==0){var f=this.form.get_form_value("drags",[o-1,"noofdrags"]);if(Number(f)!==0)for(var l in i)if(Number(i[l])===o){if(Number(f)===1){a.set("disabled",!0);break}f--}}}}},stop_selector_events:function(){e.all("fieldset#id_dropzoneheader select").detachAll()},setup_form_events:function(){e.all("fieldset#id_draggableitemheader input").on("change",function(){this.set_options_for_drag_item_selectors()},this),e.all("fieldset#id_draggableitemheader select").on("change",function(){this.set_options_for_drag_item_selectors()},this),e.all("fieldset#id_dropzoneheader select").on("change",function(){this.set_options_for_drag_item_selectors()},this)},form:{to_name_with_index:function(e,t){var n=e;for(var r=0;r. + +/** + * This is the question editing form code. + */ +var DDMARKERFORMNAME = 'moodle-qtype_ddmarker-form'; +var DDMARKER_FORM = function() { + DDMARKER_FORM.superclass.constructor.apply(this, arguments); +}; +Y.extend(DDMARKER_FORM, M.qtype_ddmarker.dd_base_class, { + fp : null, + + initializer : function() { + this.fp = this.file_pickers(); + var tn = Y.one(this.get('topnode')); + tn.one('div.fcontainer').append( + '
' + + '
' + + '
' + + '
' + + '
' + + '
'); + this.doc = this.doc_structure(this); + this.stop_selector_events(); + this.set_options_for_drag_item_selectors(); + this.setup_form_events(); + Y.later(500, this, this.update_drop_zones, [], true); + Y.after(this.load_bg_image, M.form_filepicker, 'callback', this); + this.load_bg_image(); + }, + + load_bg_image : function() { + var bgimageurl = this.fp.file('bgimage').href; + if (bgimageurl !== null) { + this.doc.load_bg_img(bgimageurl); + + 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); + } + }, + + constrain_image_size : function (e) { + var maxsize = this.get('maxsizes').bgimage; + 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); + }, + + update_drop_zones : function () { + + // Set up drop zones. + if (this.graphics !== null) { + this.graphics.destroy(); + } + this.restart_colours(); + this.graphics = new Y.Graphic({render:"div.ddarea div.dropzones"}); + var noofdropzones = this.form.get_form_value('nodropzone', []); + for (var dropzoneno = 0; dropzoneno < noofdropzones; dropzoneno++) { + var dragitemno = this.form.get_form_value('drops', [dropzoneno, 'choice']); + var markertext = this.get_marker_text(dragitemno); + var shape = this.form.get_form_value('drops', [dropzoneno, 'shape']); + var coords = this.get_coords(dropzoneno); + var colourfordropzone = this.get_next_colour(); + Y.one('input#id_drops_' + dropzoneno + '_coords') + .setStyle('background-color', colourfordropzone); + this.draw_drop_zone(dropzoneno, markertext, + shape, coords, colourfordropzone, false); + } + Y.one('div.ddarea .grid') + .setXY(this.doc.bg_img().getXY()) + .setStyle('width', this.doc.bg_img().get('width')) + .setStyle('height', this.doc.bg_img().get('height')); + }, + + get_coords : function (dropzoneno) { + var coords = this.form.get_form_value('drops', [dropzoneno, 'coords']); + return coords.replace(new RegExp("\\s*", 'g'), ''); + }, + get_marker_text : function (markerno) { + if (Number(markerno) !== 0) { + var label = this.form.get_form_value('drags', [markerno - 1, 'label']); + return label.replace(new RegExp("^\\s*(.*)\\s*$"), "$1"); + } else { + return ''; + } + }, + set_options_for_drag_item_selectors : function () { + var dragitemsoptions = {0: ''}; + for (var i = 1; i <= this.form.get_form_value('noitems', []); i++) { + var label = this.get_marker_text(i); + if (label !== "") { + dragitemsoptions[i] = Y.Escape.html(label); + } + } + // Get all the currently selected drags for each drop. + var selectedvalues = []; + var selector; + for (i = 0; i < this.form.get_form_value('nodropzone', []); i++) { + selector = Y.one('#id_drops_' + i + '_choice'); + selectedvalues[i] = Number(selector.get('value')); + } + for (i = 0; i < this.form.get_form_value('nodropzone', []); i++) { + selector = Y.one('#id_drops_' + i + '_choice'); + // Remove all options for drag choice. + selector.all('option').remove(true); + // And recreate the options. + for (var value in dragitemsoptions) { + value = Number(value); + var option = ''; + selector.append(option); + var optionnode = selector.one('option[value="' + value + '"]'); + // Is this the currently selected value? + if (value === selectedvalues[i]) { + optionnode.set('selected', true); + } else { + // It is not the currently selected value, is it selectable? + if (value !== 0) { // The 'no item' option is always selectable. + // Variables to hold form values about this drag item. + var noofdrags = this.form.get_form_value('drags', [value - 1, 'noofdrags']); + if (Number(noofdrags) !== 0) { // 'noofdrags == 0' means infinite. + // Go through all selected values in drop downs. + for (var k in selectedvalues) { + // Count down 'noofdrags' and if reach zero then set disabled option for this drag item. + if (Number(selectedvalues[k]) === value) { + if (Number(noofdrags) === 1) { + optionnode.set('disabled', true); + break; + } else { + noofdrags--; + } + } + } + } + } + } + } + } + }, + + stop_selector_events : function () { + Y.all('fieldset#id_dropzoneheader select').detachAll(); + }, + + setup_form_events : function () { + //events triggered by changes to form data + + // Changes to labels. + Y.all('fieldset#id_draggableitemheader input').on('change', function () { + this.set_options_for_drag_item_selectors(); + }, this); + + // Changes to selected drag item. + Y.all('fieldset#id_draggableitemheader select').on('change', function () { + this.set_options_for_drag_item_selectors(); + }, this); + + // Change in selected item. + Y.all('fieldset#id_dropzoneheader select').on('change', function () { + this.set_options_for_drag_item_selectors(); + }, this); + }, + + /** + * 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 : DDMARKERFORMNAME, ATTRS : {maxsizes:{value:null}}}); + +M.qtype_ddmarker = M.qtype_ddmarker || {}; +M.qtype_ddmarker.init_form = function(config) { + return new DDMARKER_FORM(config); +}; + + +}, '@VERSION@', {"requires": ["moodle-qtype_ddmarker-dd", "form_filepicker", "graphics", "escape"]}); diff --git a/question/type/ddmarker/yui/dd/dd.js b/question/type/ddmarker/yui/dd/dd.js deleted file mode 100644 index f983bbd2ad1..00000000000 --- a/question/type/ddmarker/yui/dd/dd.js +++ /dev/null @@ -1,549 +0,0 @@ -YUI.add('moodle-qtype_ddmarker-dd', function(Y) { - var DDMARKERDDNAME = 'ddmarker_dd'; - var DDMARKER_DD = function() { - DDMARKER_DD.superclass.constructor.apply(this, arguments); - }; - /** - * This is the base class for the question rendering and question editing form code. - */ - Y.extend(DDMARKER_DD, Y.Base, { - doc : null, - polltimer : null, - afterimageloaddone : false, - graphics : null, - 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'); - } - if (bgdone) { - if (this.polltimer !== null) { - this.polltimer.cancel(); - this.polltimer = null; - } - 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 () { - 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; - }, - 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'); - }, - drag_items : function() { - return dragitemsarea.all('.dragitem'); - }, - drag_items_for_choice : function(choiceno) { - return dragitemsarea.all('span.dragitem.choice' + choiceno); - }, - drag_item_for_choice : function(choiceno, itemno) { - return dragitemsarea.one('span.dragitem.choice' + choiceno + - '.item' + itemno); - }, - drag_item_being_dragged : function(choiceno) { - return dragitemsarea.one('span.dragitem.beingdragged.choice' + choiceno); - }, - drag_item_home : function (choiceno) { - return dragitemsarea.one('span.draghome.choice' + choiceno); - }, - drag_item_homes : function() { - return dragitemsarea.all('span.draghome'); - }, - 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 Number(match[0]); - } - } - } - return null; - }, - inputs_for_choices : function () { - return topnode.all('input.choices'); - }, - input_for_choice : function (choiceno) { - return topnode.one('input.choice' + choiceno); - }, - marker_texts : function () { - return topnode.one('div.markertexts'); - } - }; - }, - - colours : ['#FFFFFF', '#B0C4DE', '#DCDCDC', '#D8BFD8', - '#87CEFA','#DAA520', '#FFD700', '#F0E68C'], - nextcolourindex : 0, - restart_colours : function () { - this.nextcolourindex = 0; - }, - get_next_colour : function () { - var colour = this.colours[this.nextcolourindex]; - this.nextcolourindex++; - if (this.nextcolourindex === this.colours.length) { - this.nextcolourindex = 0; - } - return colour; - }, - 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]; - }, - shapes : [], - draw_drop_zone : function (dropzoneno, markertext, shape, coords, colour, link) { - var existingmarkertext; - if (link) { - existingmarkertext = this.doc.marker_texts().one('span.markertext' + dropzoneno + ' a'); - } else { - existingmarkertext = this.doc.marker_texts().one('span.markertext' + dropzoneno); - } - - if (existingmarkertext) { - if (markertext !== '') { - existingmarkertext.setContent(markertext); - } else { - existingmarkertext.remove(true); - } - } else if (markertext !== '') { - var classnames = 'markertext markertext' + dropzoneno; - if (link) { - this.doc.marker_texts().append('' + - markertext + ''); - } else { - this.doc.marker_texts().append('' + - markertext + ''); - } - } - var drawfunc = 'draw_shape_' + shape; - if (this[drawfunc] instanceof Function){ - var xyfortext = this[drawfunc](dropzoneno, coords, colour); - if (xyfortext !== null) { - var markerspan = this.doc.top_node().one('div.ddarea div.markertexts span.markertext' + dropzoneno); - if (markerspan !== null) { - markerspan.setStyle('opacity', '0.6'); - xyfortext[0] -= markerspan.get('offsetWidth') / 2; - xyfortext[1] -= markerspan.get('offsetHeight') / 2; - markerspan.setXY(this.convert_to_window_xy(xyfortext)); - var markerspananchor = markerspan.one('a'); - if (markerspananchor !== null) { - markerspananchor.once('click', function (e, dropzoneno) { - var fill = this.shapes[dropzoneno].get('fill'); - fill.opacity = 1; - this.shapes[dropzoneno].set('fill', fill); - }, - this, - dropzoneno - ); - markerspananchor.set('tabIndex', 0); - } - } - } - } - }, - draw_shape_circle : function (dropzoneno, coords, colour) { - var coordsparts = coords.match(/(\d+),(\d+);(\d+)/); - if (coordsparts && coordsparts.length === 4) { - var xy = [Number(coordsparts[1]) - coordsparts[3], Number(coordsparts[2]) - coordsparts[3]]; - if (this.coords_in_img(xy)) { - var widthheight = [Number(coordsparts[3]) * 2, Number(coordsparts[3]) * 2]; - var shape = this.graphics.addShape({ - type: 'circle', - width: widthheight[0], - height: widthheight[1], - fill: { - color: colour, - opacity: "0.5" - }, - stroke: { - weight: 1, - color: "black" - } - }); - shape.setXY(this.convert_to_window_xy(xy)); - this.shapes[dropzoneno] = shape; - return [Number(coordsparts[1]), Number(coordsparts[2])]; - } - } - return null; - }, - draw_shape_rectangle : function (dropzoneno, coords, colour) { - var coordsparts = coords.match(/(\d+),(\d+);(\d+),(\d+)/); - if (coordsparts && coordsparts.length === 5) { - var xy = [Number(coordsparts[1]), Number(coordsparts[2])]; - var widthheight = [Number(coordsparts[3]), Number(coordsparts[4])]; - if (this.coords_in_img([xy[0] + widthheight[0], xy[1] + widthheight[1]])) { - var shape = this.graphics.addShape({ - type: 'rect', - width: widthheight[0], - height: widthheight[1], - fill: { - color: colour, - opacity: "0.5" - }, - stroke: { - weight: 1, - color: "black" - } - }); - shape.setXY(this.convert_to_window_xy(xy)); - this.shapes[dropzoneno] = shape; - return [Number(xy[0]) + widthheight[0] / 2, Number(xy[1]) + widthheight[1] / 2]; - } - } - return null; - - }, - draw_shape_polygon : function (dropzoneno, coords, colour) { - var coordsparts = coords.split(';'); - var xy = []; - for (var i in coordsparts) { - var parts = coordsparts[i].match(/^(\d+),(\d+)$/); - if (parts !== null && this.coords_in_img([parts[1], parts[2]])) { - xy[xy.length] = [parts[1], parts[2]]; - } - } - if (xy.length > 2) { - var polygon = this.graphics.addShape({ - type: "path", - stroke: { - weight: 1, - color: "black" - }, - fill: { - color: colour, - opacity : "0.5" - } - }); - var maxxy = [0,0]; - var minxy = [this.doc.bg_img().get('width'), this.doc.bg_img().get('height')]; - for (i = 0; i < xy.length; i++) { - //calculate min and max points to find center to show marker on - minxy[0] = Math.min(xy[i][0], minxy[0]); - minxy[1] = Math.min(xy[i][1], minxy[1]); - maxxy[0] = Math.max(xy[i][0], maxxy[0]); - maxxy[1] = Math.max(xy[i][1], maxxy[1]); - if (i === 0) { - polygon.moveTo(xy[i][0], xy[i][1]); - } else { - polygon.lineTo(xy[i][0], xy[i][1]); - } - } - if (Number(xy[0][0]) !== Number(xy[xy.length - 1][0]) || Number(xy[0][1]) !== Number(xy[xy.length - 1][1])) { - polygon.lineTo(xy[0][0], xy[0][1]); // Close polygon if not already closed. - } - polygon.end(); - polygon.setXY(this.doc.bg_img().getXY()); - this.shapes[dropzoneno] = polygon; - return [(minxy[0] + maxxy[0]) / 2, (minxy[1] + maxxy[1]) / 2]; - } - return null; - }, - coords_in_img : function (coords) { - return (coords[0] <= this.doc.bg_img().get('width') && - coords[1] <= this.doc.bg_img().get('height')); - } - }, { - NAME : DDMARKERDDNAME, - ATTRS : { - drops : {value : null}, - readonly : {value : false}, - topnode : {value : null} - } - }); - M.qtype_ddmarker = M.qtype_ddmarker || {}; - M.qtype_ddmarker.dd_base_class = DDMARKER_DD; - - var DDMARKERQUESTIONNAME = 'ddmarker_question'; - var DDMARKER_QUESTION = function() { - DDMARKER_QUESTION.superclass.constructor.apply(this, arguments); - }; - /** - * This is the code for question rendering. - */ - Y.extend(DDMARKER_QUESTION, M.qtype_ddmarker.dd_base_class, { - initializer : function() { - this.doc = this.doc_structure(this); - this.poll_for_image_load(null, false, 0, this.after_image_load); - this.doc.bg_img().after('load', this.poll_for_image_load, this, - false, 0, this.after_image_load); - }, - after_image_load : function () { - this.redraw_drags_and_drops(); - Y.later(2000, this, this.redraw_drags_and_drops, [], true); - }, - clone_new_drag_item : function (draghome, itemno) { - var drag = draghome.cloneNode(true); - drag.removeClass('draghome'); - drag.addClass('dragitem'); - drag.addClass('item' + itemno); - drag.one('span.markertext').setStyle('opacity', 0.6); - draghome.insert(drag, 'after'); - if (!this.get('readonly')) { - this.draggable(drag); - } - return drag; - }, - draggable : function (drag) { - var dd = new Y.DD.Drag({ - node: drag, - dragMode: 'intersect' - }).plug(Y.Plugin.DDConstrained, {constrain2node: this.doc.top_node()}); - dd.after('drag:start', function(e){ - var dragnode = e.target.get('node'); - dragnode.addClass('beingdragged'); - var choiceno = this.get_choiceno_for_node(dragnode); - var itemno = this.get_itemno_for_node(dragnode); - if (itemno !== null) { - dragnode.removeClass('item' + dragnode); - } - this.save_all_xy_for_choice(choiceno, null); - this.redraw_drags_and_drops(); - }, this); - dd.after('drag:end', function(e) { - var dragnode = e.target.get('node'); - dragnode.removeClass('beingdragged'); - var choiceno = this.get_choiceno_for_node(dragnode); - this.save_all_xy_for_choice(choiceno, dragnode); - this.redraw_drags_and_drops(); - }, this); - //--- keyboard accessibility - drag.set('tabIndex', 0); - drag.on('dragchange', this.drop_zone_key_press, this); - }, - save_all_xy_for_choice: function (choiceno, dropped) { - var coords = []; - var bgimgxy; - for (var i = 0; i <= this.doc.drag_items_for_choice(choiceno).size(); i++) { - var dragitem = this.doc.drag_item_for_choice(choiceno, i); - if (dragitem) { - dragitem.removeClass('item' + i); - if (!dragitem.hasClass('beingdragged')) { - bgimgxy = this.convert_to_bg_img_xy(dragitem.getXY()); - if (this.xy_in_bgimg(bgimgxy)) { - dragitem.removeClass('item' + i); - dragitem.addClass('item' + coords.length); - coords[coords.length] = bgimgxy; - } - } - } - } - if (dropped !== null){ - bgimgxy = this.convert_to_bg_img_xy(dropped.getXY()); - dropped.addClass('item' + coords.length); - if (this.xy_in_bgimg(bgimgxy)) { - coords[coords.length] = bgimgxy; - } - } - this.set_form_value(choiceno, coords.join(';')); - }, - reset_drag_xy : function (choiceno) { - this.set_form_value(choiceno, ''); - }, - set_form_value : function (choiceno, value) { - this.doc.input_for_choice(choiceno).set('value', value); - }, - //make sure xy value is not out of bounds of bg image - xy_in_bgimg : function (bgimgxy) { - if ((bgimgxy[0] < 0) || - (bgimgxy[1] < 0) || - (bgimgxy[0] > this.doc.bg_img().get('width')) || - (bgimgxy[1] > this.doc.bg_img().get('height'))){ - return false; - } else { - return true; - } - }, - constrain_to_bgimg : function (windowxy) { - var bgimgxy = this.convert_to_bg_img_xy(windowxy); - bgimgxy[0] = Math.max(0, bgimgxy[0]); - bgimgxy[1] = Math.max(0, bgimgxy[1]); - bgimgxy[0] = Math.min(this.doc.bg_img().get('width'), bgimgxy[0]); - bgimgxy[1] = Math.min(this.doc.bg_img().get('height'), bgimgxy[1]); - return this.convert_to_window_xy(bgimgxy); - }, - 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]; - }, - redraw_drags_and_drops : function() { - this.doc.drag_items().each(function(item) { - //if (!item.hasClass('beingdragged')){ - item.addClass('unneeded'); - //} - }, this); - this.doc.inputs_for_choices().each(function (input) { - var choiceno = this.get_choiceno_for_node(input); - var coords = this.get_coords(input); - var dragitemhome = this.doc.drag_item_home(choiceno); - for (var i = 0; i < coords.length; i++) { - var dragitem = this.doc.drag_item_for_choice(choiceno, i); - if (!dragitem || dragitem.hasClass('beingdragged')) { - dragitem = this.clone_new_drag_item(dragitemhome, i); - } else { - dragitem.removeClass('unneeded'); - } - dragitem.setXY(coords[i]); - } - }, this); - this.doc.drag_items().each(function(item) { - if (item.hasClass('unneeded') && !item.hasClass('beingdragged')) { - item.remove(true); - } - }, this); - if (this.graphics !== null) { - this.graphics.clear(); - } else { - this.graphics = new Y.Graphic( - {render:this.doc.top_node().one("div.ddarea div.dropzones")} - ); - } - if (this.get('dropzones').length !== 0) { - this.restart_colours(); - for (var dropzoneno in this.get('dropzones')) { - var colourfordropzone = this.get_next_colour(); - var d = this.get('dropzones')[dropzoneno]; - this.draw_drop_zone(dropzoneno, d.markertext, - d.shape, d.coords, colourfordropzone, true); - } - } - }, - /** - * Determine what drag items need to be shown and - * return coords of all drag items except any that are currently being dragged - * based on contents of hidden inputs and whether drags are 'infinite' or how many drags should be shown. - */ - get_coords : function (input) { - var choiceno = this.get_choiceno_for_node(input); - var fv = input.get('value'); - var infinite = input.hasClass('infinite'); - var noofdrags = this.get_noofdrags_for_node(input); - var dragging = (null !== this.doc.drag_item_being_dragged(choiceno)); - var coords = []; - if (fv !== '') { - var coordsstrings = fv.split(';'); - for (var i = 0; i < coordsstrings.length; i++) { - coords[coords.length] = this.convert_to_window_xy(coordsstrings[i].split(',')); - } - } - var displayeddrags = coords.length + (dragging ? 1 : 0); - if (infinite || (displayeddrags < noofdrags)) { - coords[coords.length] = this.drag_home_xy(choiceno); - } - return coords; - }, - drag_home_xy : function (choiceno) { - var dragitemhome = this.doc.drag_item_home(choiceno); - return [dragitemhome.getX(), dragitemhome.getY() - 12]; - }, - get_choiceno_for_node : function(node) { - return Number(this.doc.get_classname_numeric_suffix(node, 'choice')); - }, - get_itemno_for_node : function(node) { - return Number(this.doc.get_classname_numeric_suffix(node, 'item')); - }, - get_noofdrags_for_node : function(node) { - return Number(this.doc.get_classname_numeric_suffix(node, 'noofdrags')); - }, - - // Keyboard accessibility stuff below here. - drop_zone_key_press : function (e) { - var dragitem = e.target; - var xy = dragitem.getXY(); - switch (e.direction) { - case 'left' : - xy[0] -= 1; - break; - case 'right' : - xy[0] += 1; - break; - case 'down' : - xy[1] += 1; - break; - case 'up' : - xy[1] -= 1; - break; - case 'remove' : - xy = null; - break; - } - var choiceno = this.get_choiceno_for_node(dragitem); - if (xy !== null) { - xy = this.constrain_to_bgimg(xy); - } else { - xy = this.drag_home_xy(choiceno); - } - e.preventDefault(); - dragitem.setXY(xy); - this.save_all_xy_for_choice(choiceno, null); - } - }, {NAME : DDMARKERQUESTIONNAME, ATTRS : {dropzones:{value:[]}}}); - - 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': 'remove', // Space - '37': 'left', // Left arrow - '38': 'up', // Up arrow - '39': 'right', // Right arrow - '40': 'down', // Down arrow - '65': 'left', // a - '87': 'up', // w - '68': 'right', // d - '83': 'down', // s - '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_ddmarker.init_question = function(config) { - return new DDMARKER_QUESTION(config); - }; -}, '@VERSION@', { - requires:['node', 'event-resize', 'dd', 'dd-drop', 'dd-constrain', 'graphics'] -}); diff --git a/question/type/ddmarker/yui/form/form.js b/question/type/ddmarker/yui/form/form.js deleted file mode 100644 index 36f324f3252..00000000000 --- a/question/type/ddmarker/yui/form/form.js +++ /dev/null @@ -1,255 +0,0 @@ -/** - * This is the question editing form code. - */ -YUI.add('moodle-qtype_ddmarker-form', function(Y) { - var DDMARKERFORMNAME = 'ddmarker_form'; - var DDMARKER_FORM = function() { - DDMARKER_FORM.superclass.constructor.apply(this, arguments); - }; - Y.extend(DDMARKER_FORM, M.qtype_ddmarker.dd_base_class, { - fp : null, - - initializer : function() { - this.fp = this.file_pickers(); - var tn = Y.one(this.get('topnode')); - tn.one('div.fcontainer').append( - '
' + - '
' + - '
' + - '
' + - '
' + - '
'); - this.doc = this.doc_structure(this); - this.stop_selector_events(); - this.set_options_for_drag_item_selectors(); - this.setup_form_events(); - Y.later(500, this, this.update_drop_zones, [], true); - Y.after(this.load_bg_image, M.form_filepicker, 'callback', this); - this.load_bg_image(); - }, - - load_bg_image : function() { - var bgimageurl = this.fp.file('bgimage').href; - if (bgimageurl !== null) { - this.doc.load_bg_img(bgimageurl); - - 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); - } - }, - - constrain_image_size : function (e) { - var maxsize = this.get('maxsizes').bgimage; - 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); - }, - - update_drop_zones : function () { - - // Set up drop zones. - if (this.graphics !== null) { - this.graphics.destroy(); - } - this.restart_colours(); - this.graphics = new Y.Graphic({render:"div.ddarea div.dropzones"}); - var noofdropzones = this.form.get_form_value('nodropzone', []); - for (var dropzoneno = 0; dropzoneno < noofdropzones; dropzoneno++) { - var dragitemno = this.form.get_form_value('drops', [dropzoneno, 'choice']); - var markertext = this.get_marker_text(dragitemno); - var shape = this.form.get_form_value('drops', [dropzoneno, 'shape']); - var coords = this.get_coords(dropzoneno); - var colourfordropzone = this.get_next_colour(); - Y.one('input#id_drops_' + dropzoneno + '_coords') - .setStyle('background-color', colourfordropzone); - this.draw_drop_zone(dropzoneno, markertext, - shape, coords, colourfordropzone, false); - } - Y.one('div.ddarea .grid') - .setXY(this.doc.bg_img().getXY()) - .setStyle('width', this.doc.bg_img().get('width')) - .setStyle('height', this.doc.bg_img().get('height')); - }, - - get_coords : function (dropzoneno) { - var coords = this.form.get_form_value('drops', [dropzoneno, 'coords']); - return coords.replace(new RegExp("\\s*", 'g'), ''); - }, - get_marker_text : function (markerno) { - if (Number(markerno) !== 0) { - var label = this.form.get_form_value('drags', [markerno - 1, 'label']); - return label.replace(new RegExp("^\\s*(.*)\\s*$"), "$1"); - } else { - return ''; - } - }, - set_options_for_drag_item_selectors : function () { - var dragitemsoptions = {0: ''}; - for (var i = 1; i <= this.form.get_form_value('noitems', []); i++) { - var label = this.get_marker_text(i); - if (label !== "") { - dragitemsoptions[i] = Y.Escape.html(label); - } - } - // Get all the currently selected drags for each drop. - var selectedvalues = []; - var selector; - for (i = 0; i < this.form.get_form_value('nodropzone', []); i++) { - selector = Y.one('#id_drops_' + i + '_choice'); - selectedvalues[i] = Number(selector.get('value')); - } - for (i = 0; i < this.form.get_form_value('nodropzone', []); i++) { - selector = Y.one('#id_drops_' + i + '_choice'); - // Remove all options for drag choice. - selector.all('option').remove(true); - // And recreate the options. - for (var value in dragitemsoptions) { - value = Number(value); - var option = ''; - selector.append(option); - var optionnode = selector.one('option[value="' + value + '"]'); - // Is this the currently selected value? - if (value === selectedvalues[i]) { - optionnode.set('selected', true); - } else { - // It is not the currently selected value, is it selectable? - if (value !== 0) { // The 'no item' option is always selectable. - // Variables to hold form values about this drag item. - var noofdrags = this.form.get_form_value('drags', [value - 1, 'noofdrags']); - if (Number(noofdrags) !== 0) { // 'noofdrags == 0' means infinite. - // Go through all selected values in drop downs. - for (var k in selectedvalues) { - // Count down 'noofdrags' and if reach zero then set disabled option for this drag item. - if (Number(selectedvalues[k]) === value) { - if (Number(noofdrags) === 1) { - optionnode.set('disabled', true); - break; - } else { - noofdrags--; - } - } - } - } - } - } - } - } - }, - - stop_selector_events : function () { - Y.all('fieldset#id_dropzoneheader select').detachAll(); - }, - - setup_form_events : function () { - //events triggered by changes to form data - - // Changes to labels. - Y.all('fieldset#id_draggableitemheader input').on('change', function () { - this.set_options_for_drag_item_selectors(); - }, this); - - // Changes to selected drag item. - Y.all('fieldset#id_draggableitemheader select').on('change', function () { - this.set_options_for_drag_item_selectors(); - }, this); - - // Change in selected item. - Y.all('fieldset#id_dropzoneheader select').on('change', function () { - this.set_options_for_drag_item_selectors(); - }, this); - }, - - /** - * 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 : DDMARKERFORMNAME, ATTRS : {maxsizes:{value:null}}}); - M.qtype_ddmarker = M.qtype_ddmarker || {}; - M.qtype_ddmarker.init_form = function(config) { - return new DDMARKER_FORM(config); - }; -}, '@VERSION@', { - requires:['moodle-qtype_ddmarker-dd', 'form_filepicker', 'graphics', 'escape'] -}); diff --git a/question/type/ddmarker/yui/src/ddmarker/build.json b/question/type/ddmarker/yui/src/ddmarker/build.json new file mode 100644 index 00000000000..845329ec4ed --- /dev/null +++ b/question/type/ddmarker/yui/src/ddmarker/build.json @@ -0,0 +1,10 @@ +{ + "name": "moodle-qtype_ddmarker-dd", + "builds": { + "moodle-qtype_ddmarker-dd": { + "jsfiles": [ + "ddmarker.js" + ] + } + } +} diff --git a/question/type/ddmarker/yui/src/ddmarker/js/ddmarker.js b/question/type/ddmarker/yui/src/ddmarker/js/ddmarker.js new file mode 100644 index 00000000000..bb89b629771 --- /dev/null +++ b/question/type/ddmarker/yui/src/ddmarker/js/ddmarker.js @@ -0,0 +1,560 @@ +// 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 DDMARKERDDNAME = 'moodle-qtype_ddmarker-dd'; +var DDMARKER_DD = function() { + DDMARKER_DD.superclass.constructor.apply(this, arguments); +}; +/** + * This is the base class for the question rendering and question editing form code. + */ +Y.extend(DDMARKER_DD, Y.Base, { + doc : null, + polltimer : null, + afterimageloaddone : false, + graphics : null, + 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'); + } + if (bgdone) { + if (this.polltimer !== null) { + this.polltimer.cancel(); + this.polltimer = null; + } + 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 () { + 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; + }, + 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'); + }, + drag_items : function() { + return dragitemsarea.all('.dragitem'); + }, + drag_items_for_choice : function(choiceno) { + return dragitemsarea.all('span.dragitem.choice' + choiceno); + }, + drag_item_for_choice : function(choiceno, itemno) { + return dragitemsarea.one('span.dragitem.choice' + choiceno + + '.item' + itemno); + }, + drag_item_being_dragged : function(choiceno) { + return dragitemsarea.one('span.dragitem.beingdragged.choice' + choiceno); + }, + drag_item_home : function (choiceno) { + return dragitemsarea.one('span.draghome.choice' + choiceno); + }, + drag_item_homes : function() { + return dragitemsarea.all('span.draghome'); + }, + 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 Number(match[0]); + } + } + } + return null; + }, + inputs_for_choices : function () { + return topnode.all('input.choices'); + }, + input_for_choice : function (choiceno) { + return topnode.one('input.choice' + choiceno); + }, + marker_texts : function () { + return topnode.one('div.markertexts'); + } + }; + }, + + colours : ['#FFFFFF', '#B0C4DE', '#DCDCDC', '#D8BFD8', + '#87CEFA','#DAA520', '#FFD700', '#F0E68C'], + nextcolourindex : 0, + restart_colours : function () { + this.nextcolourindex = 0; + }, + get_next_colour : function () { + var colour = this.colours[this.nextcolourindex]; + this.nextcolourindex++; + if (this.nextcolourindex === this.colours.length) { + this.nextcolourindex = 0; + } + return colour; + }, + 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]; + }, + shapes : [], + draw_drop_zone : function (dropzoneno, markertext, shape, coords, colour, link) { + var existingmarkertext; + if (link) { + existingmarkertext = this.doc.marker_texts().one('span.markertext' + dropzoneno + ' a'); + } else { + existingmarkertext = this.doc.marker_texts().one('span.markertext' + dropzoneno); + } + + if (existingmarkertext) { + if (markertext !== '') { + existingmarkertext.setContent(markertext); + } else { + existingmarkertext.remove(true); + } + } else if (markertext !== '') { + var classnames = 'markertext markertext' + dropzoneno; + if (link) { + this.doc.marker_texts().append('' + + markertext + ''); + } else { + this.doc.marker_texts().append('' + + markertext + ''); + } + } + var drawfunc = 'draw_shape_' + shape; + if (this[drawfunc] instanceof Function){ + var xyfortext = this[drawfunc](dropzoneno, coords, colour); + if (xyfortext !== null) { + var markerspan = this.doc.top_node().one('div.ddarea div.markertexts span.markertext' + dropzoneno); + if (markerspan !== null) { + markerspan.setStyle('opacity', '0.6'); + xyfortext[0] -= markerspan.get('offsetWidth') / 2; + xyfortext[1] -= markerspan.get('offsetHeight') / 2; + markerspan.setXY(this.convert_to_window_xy(xyfortext)); + var markerspananchor = markerspan.one('a'); + if (markerspananchor !== null) { + markerspananchor.once('click', function (e, dropzoneno) { + var fill = this.shapes[dropzoneno].get('fill'); + fill.opacity = 1; + this.shapes[dropzoneno].set('fill', fill); + }, + this, + dropzoneno + ); + markerspananchor.set('tabIndex', 0); + } + } + } + } + }, + draw_shape_circle : function (dropzoneno, coords, colour) { + var coordsparts = coords.match(/(\d+),(\d+);(\d+)/); + if (coordsparts && coordsparts.length === 4) { + var xy = [Number(coordsparts[1]) - coordsparts[3], Number(coordsparts[2]) - coordsparts[3]]; + if (this.coords_in_img(xy)) { + var widthheight = [Number(coordsparts[3]) * 2, Number(coordsparts[3]) * 2]; + var shape = this.graphics.addShape({ + type: 'circle', + width: widthheight[0], + height: widthheight[1], + fill: { + color: colour, + opacity: "0.5" + }, + stroke: { + weight: 1, + color: "black" + } + }); + shape.setXY(this.convert_to_window_xy(xy)); + this.shapes[dropzoneno] = shape; + return [Number(coordsparts[1]), Number(coordsparts[2])]; + } + } + return null; + }, + draw_shape_rectangle : function (dropzoneno, coords, colour) { + var coordsparts = coords.match(/(\d+),(\d+);(\d+),(\d+)/); + if (coordsparts && coordsparts.length === 5) { + var xy = [Number(coordsparts[1]), Number(coordsparts[2])]; + var widthheight = [Number(coordsparts[3]), Number(coordsparts[4])]; + if (this.coords_in_img([xy[0] + widthheight[0], xy[1] + widthheight[1]])) { + var shape = this.graphics.addShape({ + type: 'rect', + width: widthheight[0], + height: widthheight[1], + fill: { + color: colour, + opacity: "0.5" + }, + stroke: { + weight: 1, + color: "black" + } + }); + shape.setXY(this.convert_to_window_xy(xy)); + this.shapes[dropzoneno] = shape; + return [Number(xy[0]) + widthheight[0] / 2, Number(xy[1]) + widthheight[1] / 2]; + } + } + return null; + + }, + draw_shape_polygon : function (dropzoneno, coords, colour) { + var coordsparts = coords.split(';'); + var xy = []; + for (var i in coordsparts) { + var parts = coordsparts[i].match(/^(\d+),(\d+)$/); + if (parts !== null && this.coords_in_img([parts[1], parts[2]])) { + xy[xy.length] = [parts[1], parts[2]]; + } + } + if (xy.length > 2) { + var polygon = this.graphics.addShape({ + type: "path", + stroke: { + weight: 1, + color: "black" + }, + fill: { + color: colour, + opacity : "0.5" + } + }); + var maxxy = [0,0]; + var minxy = [this.doc.bg_img().get('width'), this.doc.bg_img().get('height')]; + for (i = 0; i < xy.length; i++) { + //calculate min and max points to find center to show marker on + minxy[0] = Math.min(xy[i][0], minxy[0]); + minxy[1] = Math.min(xy[i][1], minxy[1]); + maxxy[0] = Math.max(xy[i][0], maxxy[0]); + maxxy[1] = Math.max(xy[i][1], maxxy[1]); + if (i === 0) { + polygon.moveTo(xy[i][0], xy[i][1]); + } else { + polygon.lineTo(xy[i][0], xy[i][1]); + } + } + if (Number(xy[0][0]) !== Number(xy[xy.length - 1][0]) || Number(xy[0][1]) !== Number(xy[xy.length - 1][1])) { + polygon.lineTo(xy[0][0], xy[0][1]); // Close polygon if not already closed. + } + polygon.end(); + polygon.setXY(this.doc.bg_img().getXY()); + this.shapes[dropzoneno] = polygon; + return [(minxy[0] + maxxy[0]) / 2, (minxy[1] + maxxy[1]) / 2]; + } + return null; + }, + coords_in_img : function (coords) { + return (coords[0] <= this.doc.bg_img().get('width') && + coords[1] <= this.doc.bg_img().get('height')); + } +}, { + NAME : DDMARKERDDNAME, + ATTRS : { + drops : {value : null}, + readonly : {value : false}, + topnode : {value : null} + } +}); +M.qtype_ddmarker = M.qtype_ddmarker || {}; +M.qtype_ddmarker.dd_base_class = DDMARKER_DD; + +var DDMARKERQUESTIONNAME = 'ddmarker_question'; +var DDMARKER_QUESTION = function() { + DDMARKER_QUESTION.superclass.constructor.apply(this, arguments); +}; +/** + * This is the code for question rendering. + */ +Y.extend(DDMARKER_QUESTION, M.qtype_ddmarker.dd_base_class, { + initializer : function() { + this.doc = this.doc_structure(this); + this.poll_for_image_load(null, false, 0, this.after_image_load); + this.doc.bg_img().after('load', this.poll_for_image_load, this, + false, 0, this.after_image_load); + }, + after_image_load : function () { + this.redraw_drags_and_drops(); + Y.later(2000, this, this.redraw_drags_and_drops, [], true); + }, + clone_new_drag_item : function (draghome, itemno) { + var drag = draghome.cloneNode(true); + drag.removeClass('draghome'); + drag.addClass('dragitem'); + drag.addClass('item' + itemno); + drag.one('span.markertext').setStyle('opacity', 0.6); + draghome.insert(drag, 'after'); + if (!this.get('readonly')) { + this.draggable(drag); + } + return drag; + }, + draggable : function (drag) { + var dd = new Y.DD.Drag({ + node: drag, + dragMode: 'intersect' + }).plug(Y.Plugin.DDConstrained, {constrain2node: this.doc.top_node()}); + dd.after('drag:start', function(e){ + var dragnode = e.target.get('node'); + dragnode.addClass('beingdragged'); + var choiceno = this.get_choiceno_for_node(dragnode); + var itemno = this.get_itemno_for_node(dragnode); + if (itemno !== null) { + dragnode.removeClass('item' + dragnode); + } + this.save_all_xy_for_choice(choiceno, null); + this.redraw_drags_and_drops(); + }, this); + dd.after('drag:end', function(e) { + var dragnode = e.target.get('node'); + dragnode.removeClass('beingdragged'); + var choiceno = this.get_choiceno_for_node(dragnode); + this.save_all_xy_for_choice(choiceno, dragnode); + this.redraw_drags_and_drops(); + }, this); + //--- keyboard accessibility + drag.set('tabIndex', 0); + drag.on('dragchange', this.drop_zone_key_press, this); + }, + save_all_xy_for_choice: function (choiceno, dropped) { + var coords = []; + var bgimgxy; + for (var i = 0; i <= this.doc.drag_items_for_choice(choiceno).size(); i++) { + var dragitem = this.doc.drag_item_for_choice(choiceno, i); + if (dragitem) { + dragitem.removeClass('item' + i); + if (!dragitem.hasClass('beingdragged')) { + bgimgxy = this.convert_to_bg_img_xy(dragitem.getXY()); + if (this.xy_in_bgimg(bgimgxy)) { + dragitem.removeClass('item' + i); + dragitem.addClass('item' + coords.length); + coords[coords.length] = bgimgxy; + } + } + } + } + if (dropped !== null){ + bgimgxy = this.convert_to_bg_img_xy(dropped.getXY()); + dropped.addClass('item' + coords.length); + if (this.xy_in_bgimg(bgimgxy)) { + coords[coords.length] = bgimgxy; + } + } + this.set_form_value(choiceno, coords.join(';')); + }, + reset_drag_xy : function (choiceno) { + this.set_form_value(choiceno, ''); + }, + set_form_value : function (choiceno, value) { + this.doc.input_for_choice(choiceno).set('value', value); + }, + //make sure xy value is not out of bounds of bg image + xy_in_bgimg : function (bgimgxy) { + if ((bgimgxy[0] < 0) || + (bgimgxy[1] < 0) || + (bgimgxy[0] > this.doc.bg_img().get('width')) || + (bgimgxy[1] > this.doc.bg_img().get('height'))){ + return false; + } else { + return true; + } + }, + constrain_to_bgimg : function (windowxy) { + var bgimgxy = this.convert_to_bg_img_xy(windowxy); + bgimgxy[0] = Math.max(0, bgimgxy[0]); + bgimgxy[1] = Math.max(0, bgimgxy[1]); + bgimgxy[0] = Math.min(this.doc.bg_img().get('width'), bgimgxy[0]); + bgimgxy[1] = Math.min(this.doc.bg_img().get('height'), bgimgxy[1]); + return this.convert_to_window_xy(bgimgxy); + }, + 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]; + }, + redraw_drags_and_drops : function() { + this.doc.drag_items().each(function(item) { + //if (!item.hasClass('beingdragged')){ + item.addClass('unneeded'); + //} + }, this); + this.doc.inputs_for_choices().each(function (input) { + var choiceno = this.get_choiceno_for_node(input); + var coords = this.get_coords(input); + var dragitemhome = this.doc.drag_item_home(choiceno); + for (var i = 0; i < coords.length; i++) { + var dragitem = this.doc.drag_item_for_choice(choiceno, i); + if (!dragitem || dragitem.hasClass('beingdragged')) { + dragitem = this.clone_new_drag_item(dragitemhome, i); + } else { + dragitem.removeClass('unneeded'); + } + dragitem.setXY(coords[i]); + } + }, this); + this.doc.drag_items().each(function(item) { + if (item.hasClass('unneeded') && !item.hasClass('beingdragged')) { + item.remove(true); + } + }, this); + if (this.graphics !== null) { + this.graphics.clear(); + } else { + this.graphics = new Y.Graphic( + {render:this.doc.top_node().one("div.ddarea div.dropzones")} + ); + } + if (this.get('dropzones').length !== 0) { + this.restart_colours(); + for (var dropzoneno in this.get('dropzones')) { + var colourfordropzone = this.get_next_colour(); + var d = this.get('dropzones')[dropzoneno]; + this.draw_drop_zone(dropzoneno, d.markertext, + d.shape, d.coords, colourfordropzone, true); + } + } + }, + /** + * Determine what drag items need to be shown and + * return coords of all drag items except any that are currently being dragged + * based on contents of hidden inputs and whether drags are 'infinite' or how many drags should be shown. + */ + get_coords : function (input) { + var choiceno = this.get_choiceno_for_node(input); + var fv = input.get('value'); + var infinite = input.hasClass('infinite'); + var noofdrags = this.get_noofdrags_for_node(input); + var dragging = (null !== this.doc.drag_item_being_dragged(choiceno)); + var coords = []; + if (fv !== '') { + var coordsstrings = fv.split(';'); + for (var i = 0; i < coordsstrings.length; i++) { + coords[coords.length] = this.convert_to_window_xy(coordsstrings[i].split(',')); + } + } + var displayeddrags = coords.length + (dragging ? 1 : 0); + if (infinite || (displayeddrags < noofdrags)) { + coords[coords.length] = this.drag_home_xy(choiceno); + } + return coords; + }, + drag_home_xy : function (choiceno) { + var dragitemhome = this.doc.drag_item_home(choiceno); + return [dragitemhome.getX(), dragitemhome.getY() - 12]; + }, + get_choiceno_for_node : function(node) { + return Number(this.doc.get_classname_numeric_suffix(node, 'choice')); + }, + get_itemno_for_node : function(node) { + return Number(this.doc.get_classname_numeric_suffix(node, 'item')); + }, + get_noofdrags_for_node : function(node) { + return Number(this.doc.get_classname_numeric_suffix(node, 'noofdrags')); + }, + + // Keyboard accessibility stuff below here. + drop_zone_key_press : function (e) { + var dragitem = e.target; + var xy = dragitem.getXY(); + switch (e.direction) { + case 'left' : + xy[0] -= 1; + break; + case 'right' : + xy[0] += 1; + break; + case 'down' : + xy[1] += 1; + break; + case 'up' : + xy[1] -= 1; + break; + case 'remove' : + xy = null; + break; + } + var choiceno = this.get_choiceno_for_node(dragitem); + if (xy !== null) { + xy = this.constrain_to_bgimg(xy); + } else { + xy = this.drag_home_xy(choiceno); + } + e.preventDefault(); + dragitem.setXY(xy); + this.save_all_xy_for_choice(choiceno, null); + } +}, {NAME : DDMARKERQUESTIONNAME, ATTRS : {dropzones:{value:[]}}}); + +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': 'remove', // Space + '37': 'left', // Left arrow + '38': 'up', // Up arrow + '39': 'right', // Right arrow + '40': 'down', // Down arrow + '65': 'left', // a + '87': 'up', // w + '68': 'right', // d + '83': 'down', // s + '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_ddmarker.init_question = function(config) { + return new DDMARKER_QUESTION(config); +}; diff --git a/question/type/ddmarker/yui/src/ddmarker/meta/ddmarker.json b/question/type/ddmarker/yui/src/ddmarker/meta/ddmarker.json new file mode 100644 index 00000000000..c04e7a42210 --- /dev/null +++ b/question/type/ddmarker/yui/src/ddmarker/meta/ddmarker.json @@ -0,0 +1,12 @@ +{ + "moodle-qtype_ddmarker-dd": { + "requires": [ + "node", + "event-resize", + "dd", + "dd-drop", + "dd-constrain", + "graphics" + ] + } +} \ No newline at end of file diff --git a/question/type/ddmarker/yui/src/form/build.json b/question/type/ddmarker/yui/src/form/build.json new file mode 100644 index 00000000000..8a8f5dc4a4a --- /dev/null +++ b/question/type/ddmarker/yui/src/form/build.json @@ -0,0 +1,10 @@ +{ + "name": "moodle-qtype_ddmarker-form", + "builds": { + "moodle-qtype_ddmarker-form": { + "jsfiles": [ + "form.js" + ] + } + } +} diff --git a/question/type/ddmarker/yui/src/form/js/form.js b/question/type/ddmarker/yui/src/form/js/form.js new file mode 100644 index 00000000000..e8ac876a2f5 --- /dev/null +++ b/question/type/ddmarker/yui/src/form/js/form.js @@ -0,0 +1,267 @@ +// 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 DDMARKERFORMNAME = 'moodle-qtype_ddmarker-form'; +var DDMARKER_FORM = function() { + DDMARKER_FORM.superclass.constructor.apply(this, arguments); +}; +Y.extend(DDMARKER_FORM, M.qtype_ddmarker.dd_base_class, { + fp : null, + + initializer : function() { + this.fp = this.file_pickers(); + var tn = Y.one(this.get('topnode')); + tn.one('div.fcontainer').append( + '
' + + '
' + + '
' + + '
' + + '
' + + '
'); + this.doc = this.doc_structure(this); + this.stop_selector_events(); + this.set_options_for_drag_item_selectors(); + this.setup_form_events(); + Y.later(500, this, this.update_drop_zones, [], true); + Y.after(this.load_bg_image, M.form_filepicker, 'callback', this); + this.load_bg_image(); + }, + + load_bg_image : function() { + var bgimageurl = this.fp.file('bgimage').href; + if (bgimageurl !== null) { + this.doc.load_bg_img(bgimageurl); + + 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); + } + }, + + constrain_image_size : function (e) { + var maxsize = this.get('maxsizes').bgimage; + 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); + }, + + update_drop_zones : function () { + + // Set up drop zones. + if (this.graphics !== null) { + this.graphics.destroy(); + } + this.restart_colours(); + this.graphics = new Y.Graphic({render:"div.ddarea div.dropzones"}); + var noofdropzones = this.form.get_form_value('nodropzone', []); + for (var dropzoneno = 0; dropzoneno < noofdropzones; dropzoneno++) { + var dragitemno = this.form.get_form_value('drops', [dropzoneno, 'choice']); + var markertext = this.get_marker_text(dragitemno); + var shape = this.form.get_form_value('drops', [dropzoneno, 'shape']); + var coords = this.get_coords(dropzoneno); + var colourfordropzone = this.get_next_colour(); + Y.one('input#id_drops_' + dropzoneno + '_coords') + .setStyle('background-color', colourfordropzone); + this.draw_drop_zone(dropzoneno, markertext, + shape, coords, colourfordropzone, false); + } + Y.one('div.ddarea .grid') + .setXY(this.doc.bg_img().getXY()) + .setStyle('width', this.doc.bg_img().get('width')) + .setStyle('height', this.doc.bg_img().get('height')); + }, + + get_coords : function (dropzoneno) { + var coords = this.form.get_form_value('drops', [dropzoneno, 'coords']); + return coords.replace(new RegExp("\\s*", 'g'), ''); + }, + get_marker_text : function (markerno) { + if (Number(markerno) !== 0) { + var label = this.form.get_form_value('drags', [markerno - 1, 'label']); + return label.replace(new RegExp("^\\s*(.*)\\s*$"), "$1"); + } else { + return ''; + } + }, + set_options_for_drag_item_selectors : function () { + var dragitemsoptions = {0: ''}; + for (var i = 1; i <= this.form.get_form_value('noitems', []); i++) { + var label = this.get_marker_text(i); + if (label !== "") { + dragitemsoptions[i] = Y.Escape.html(label); + } + } + // Get all the currently selected drags for each drop. + var selectedvalues = []; + var selector; + for (i = 0; i < this.form.get_form_value('nodropzone', []); i++) { + selector = Y.one('#id_drops_' + i + '_choice'); + selectedvalues[i] = Number(selector.get('value')); + } + for (i = 0; i < this.form.get_form_value('nodropzone', []); i++) { + selector = Y.one('#id_drops_' + i + '_choice'); + // Remove all options for drag choice. + selector.all('option').remove(true); + // And recreate the options. + for (var value in dragitemsoptions) { + value = Number(value); + var option = ''; + selector.append(option); + var optionnode = selector.one('option[value="' + value + '"]'); + // Is this the currently selected value? + if (value === selectedvalues[i]) { + optionnode.set('selected', true); + } else { + // It is not the currently selected value, is it selectable? + if (value !== 0) { // The 'no item' option is always selectable. + // Variables to hold form values about this drag item. + var noofdrags = this.form.get_form_value('drags', [value - 1, 'noofdrags']); + if (Number(noofdrags) !== 0) { // 'noofdrags == 0' means infinite. + // Go through all selected values in drop downs. + for (var k in selectedvalues) { + // Count down 'noofdrags' and if reach zero then set disabled option for this drag item. + if (Number(selectedvalues[k]) === value) { + if (Number(noofdrags) === 1) { + optionnode.set('disabled', true); + break; + } else { + noofdrags--; + } + } + } + } + } + } + } + } + }, + + stop_selector_events : function () { + Y.all('fieldset#id_dropzoneheader select').detachAll(); + }, + + setup_form_events : function () { + //events triggered by changes to form data + + // Changes to labels. + Y.all('fieldset#id_draggableitemheader input').on('change', function () { + this.set_options_for_drag_item_selectors(); + }, this); + + // Changes to selected drag item. + Y.all('fieldset#id_draggableitemheader select').on('change', function () { + this.set_options_for_drag_item_selectors(); + }, this); + + // Change in selected item. + Y.all('fieldset#id_dropzoneheader select').on('change', function () { + this.set_options_for_drag_item_selectors(); + }, this); + }, + + /** + * 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 : DDMARKERFORMNAME, ATTRS : {maxsizes:{value:null}}}); + +M.qtype_ddmarker = M.qtype_ddmarker || {}; +M.qtype_ddmarker.init_form = function(config) { + return new DDMARKER_FORM(config); +}; diff --git a/question/type/ddmarker/yui/src/form/meta/form.json b/question/type/ddmarker/yui/src/form/meta/form.json new file mode 100644 index 00000000000..123ac557976 --- /dev/null +++ b/question/type/ddmarker/yui/src/form/meta/form.json @@ -0,0 +1,10 @@ +{ + "moodle-qtype_ddmarker-form": { + "requires": [ + "moodle-qtype_ddmarker-dd", + "form_filepicker", + "graphics", + "escape" + ] + } +} -- 2.11.4.GIT