1 // This file is part of Moodle - http://moodle.org/
3 // Moodle is free software: you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation, either version 3 of the License, or
6 // (at your option) any later version.
8 // Moodle is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 // GNU General Public License for more details.
13 // You should have received a copy of the GNU General Public License
14 // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
17 * This is the question editing form code.
19 var DDMARKERFORMNAME = 'moodle-qtype_ddmarker-form';
20 var DDMARKER_FORM = function() {
21 DDMARKER_FORM.superclass.constructor.apply(this, arguments);
23 Y.extend(DDMARKER_FORM, M.qtype_ddmarker.dd_base_class, {
26 initializer : function() {
27 var pendingid = 'qtype_ddmarker-form-' + Math.random().toString(36).slice(2); // Random string.
28 M.util.js_pending(pendingid);
29 this.fp = this.file_pickers();
30 var tn = Y.one(this.get('topnode'));
31 tn.one('div.fcontainer').append(
32 '<div class="ddarea">' +
33 '<div class="markertexts"></div>' +
34 '<div class="droparea"></div>' +
35 '<div class="dropzones"></div>' +
36 '<div class="grid"></div>' +
38 this.doc = this.doc_structure(this);
39 this.stop_selector_events();
40 this.set_options_for_drag_item_selectors();
41 this.setup_form_events();
42 Y.later(500, this, this.update_drop_zones, [pendingid], true);
43 Y.after(this.load_bg_image, M.form_filepicker, 'callback', this);
47 load_bg_image : function() {
48 var bgimageurl = this.fp.file('bgimage').href;
49 if (bgimageurl !== null) {
50 this.doc.load_bg_img(bgimageurl);
52 var drop = new Y.DD.Drop({
53 node: this.doc.bg_img()
56 // Listen for a drop:hit on the background image.
57 drop.on('drop:hit', function(e) {
58 e.drag.get('node').setData('gooddrop', true);
61 this.afterimageloaddone = false;
62 this.doc.bg_img().on('load', this.constrain_image_size, this);
66 constrain_image_size : function (e) {
67 var maxsize = this.get('maxsizes').bgimage;
68 var reduceby = Math.max(e.target.get('width') / maxsize.width,
69 e.target.get('height') / maxsize.height);
71 e.target.set('width', Math.floor(e.target.get('width') / reduceby));
73 e.target.addClass('constrained');
74 e.target.detach('load', this.constrain_image_size);
77 update_drop_zones : function (pendingid) {
80 if (this.graphics !== null) {
81 this.graphics.destroy();
83 this.restart_colours();
84 this.graphics = new Y.Graphic({render:"div.ddarea div.dropzones"});
85 var noofdropzones = this.form.get_form_value('nodropzone', []);
86 for (var dropzoneno = 0; dropzoneno < noofdropzones; dropzoneno++) {
87 var dragitemno = this.form.get_form_value('drops', [dropzoneno, 'choice']);
88 var markertext = this.get_marker_text(dragitemno);
89 var shape = this.form.get_form_value('drops', [dropzoneno, 'shape']);
90 var coords = this.get_coords(dropzoneno);
91 var colourfordropzone = this.get_next_colour();
92 Y.one('input#id_drops_' + dropzoneno + '_coords')
93 .setStyle('background-color', colourfordropzone);
94 this.draw_drop_zone(dropzoneno, markertext,
95 shape, coords, colourfordropzone, false);
97 if (this.doc.bg_img()) {
98 Y.one('div.ddarea .grid')
99 .setXY(this.doc.bg_img().getXY())
100 .setStyle('width', this.doc.bg_img().get('width'))
101 .setStyle('height', this.doc.bg_img().get('height'));
103 M.util.js_complete(pendingid);
106 get_coords : function (dropzoneno) {
107 var coords = this.form.get_form_value('drops', [dropzoneno, 'coords']);
108 return coords.replace(new RegExp("\\s*", 'g'), '');
110 get_marker_text : function (markerno) {
111 if (Number(markerno) !== 0) {
112 var label = this.form.get_form_value('drags', [markerno - 1, 'label']);
113 return label.replace(new RegExp("^\\s*(.*)\\s*$"), "$1");
118 set_options_for_drag_item_selectors : function () {
119 var dragitemsoptions = {0: ''};
120 for (var i = 1; i <= this.form.get_form_value('noitems', []); i++) {
121 var label = this.get_marker_text(i);
123 dragitemsoptions[i] = Y.Escape.html(label);
126 // Get all the currently selected drags for each drop.
127 var selectedvalues = [];
129 for (i = 0; i < this.form.get_form_value('nodropzone', []); i++) {
130 selector = Y.one('#id_drops_' + i + '_choice');
131 selectedvalues[i] = Number(selector.get('value'));
133 for (i = 0; i < this.form.get_form_value('nodropzone', []); i++) {
134 selector = Y.one('#id_drops_' + i + '_choice');
135 // Remove all options for drag choice.
136 selector.all('option').remove(true);
137 // And recreate the options.
138 for (var value in dragitemsoptions) {
139 value = Number(value);
140 var option = '<option value="' + value + '">' + dragitemsoptions[value] + '</option>';
141 selector.append(option);
142 var optionnode = selector.one('option[value="' + value + '"]');
143 // Is this the currently selected value?
144 if (value === selectedvalues[i]) {
145 optionnode.set('selected', true);
147 // It is not the currently selected value, is it selectable?
148 if (value !== 0) { // The 'no item' option is always selectable.
149 // Variables to hold form values about this drag item.
150 var noofdrags = this.form.get_form_value('drags', [value - 1, 'noofdrags']);
151 if (Number(noofdrags) !== 0) { // 'noofdrags == 0' means infinite.
152 // Go through all selected values in drop downs.
153 for (var k in selectedvalues) {
154 // Count down 'noofdrags' and if reach zero then set disabled option for this drag item.
155 if (Number(selectedvalues[k]) === value) {
156 if (Number(noofdrags) === 1) {
157 optionnode.set('disabled', true);
171 stop_selector_events : function () {
172 Y.all('fieldset#id_dropzoneheader select').detachAll();
175 setup_form_events : function () {
176 //events triggered by changes to form data
178 // Changes to labels.
179 Y.all('fieldset#id_draggableitemheader input').on('change', function () {
180 this.set_options_for_drag_item_selectors();
183 // Changes to selected drag item.
184 Y.all('fieldset#id_draggableitemheader select').on('change', function () {
185 this.set_options_for_drag_item_selectors();
188 // Change in selected item.
189 Y.all('fieldset#id_dropzoneheader select').on('change', function () {
190 this.set_options_for_drag_item_selectors();
195 * Low level operations on form.
198 to_name_with_index : function(name, indexes) {
199 var indexstring = name;
200 for (var i = 0; i < indexes.length; i++) {
201 indexstring = indexstring + '[' + indexes[i] + ']';
205 get_el : function (name, indexes) {
206 var form = document.getElementById('mform1');
207 return form.elements[this.to_name_with_index(name, indexes)];
209 get_form_value : function(name, indexes) {
210 var el = this.get_el(name, indexes);
211 if (el.type === 'checkbox') {
217 set_form_value : function(name, indexes, value) {
218 var el = this.get_el(name, indexes);
219 if (el.type === 'checkbox') {
225 from_name_with_index : function(name) {
227 toreturn.indexes = [];
228 var bracket = name.indexOf('[');
229 toreturn.name = name.substring(0, bracket);
230 while (bracket !== -1) {
231 var end = name.indexOf(']', bracket + 1);
232 toreturn.indexes.push(name.substring(bracket + 1, end));
233 bracket = name.indexOf('[', end + 1);
239 file_pickers : function () {
240 var draftitemidstoname;
241 var nametoparentnode;
242 if (draftitemidstoname === undefined) {
243 draftitemidstoname = {};
244 nametoparentnode = {};
245 var filepickers = Y.all('form.mform input.filepickerhidden');
246 filepickers.each(function(filepicker) {
247 draftitemidstoname[filepicker.get('value')] = filepicker.get('name');
248 nametoparentnode[filepicker.get('name')] = filepicker.get('parentNode');
252 file : function (name) {
253 var parentnode = nametoparentnode[name];
254 var fileanchor = parentnode.one('div.filepicker-filelist a');
256 return {href : fileanchor.get('href'), name : fileanchor.get('innerHTML')};
258 return {href : null, name : null};
261 name : function (draftitemid) {
262 return draftitemidstoname[draftitemid];
267 },{NAME : DDMARKERFORMNAME, ATTRS : {maxsizes:{value:null}}});
269 M.qtype_ddmarker = M.qtype_ddmarker || {};
270 M.qtype_ddmarker.init_form = function(config) {
271 return new DDMARKER_FORM(config);