PageRenderTime 48ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 1ms

/question/type/calculatedsimple/edit_calculatedsimple_form.php

https://bitbucket.org/moodle/moodle
PHP | 624 lines | 477 code | 62 blank | 85 comment | 89 complexity | 3862ca3607e6d25ec681527646a23c66 MD5 | raw file
Possible License(s): Apache-2.0, LGPL-2.1, BSD-3-Clause, MIT, GPL-3.0
  1. <?php
  2. // This file is part of Moodle - http://moodle.org/
  3. //
  4. // Moodle is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // Moodle is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU General Public License
  15. // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
  16. /**
  17. * Defines the editing form for the calculated simplequestion type.
  18. *
  19. * @package qtype
  20. * @subpackage calculatedsimple
  21. * @copyright 2007 Jamie Pratt me@jamiep.org
  22. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23. */
  24. defined('MOODLE_INTERNAL') || die();
  25. require_once($CFG->dirroot . '/question/type/calculated/edit_calculated_form.php');
  26. /**
  27. * Editing form for the calculated simplequestion type.
  28. *
  29. * @copyright 2007 Jamie Pratt me@jamiep.org
  30. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  31. */
  32. class qtype_calculatedsimple_edit_form extends qtype_calculated_edit_form {
  33. /**
  34. * Handle to the question type for this question.
  35. *
  36. * @var question_calculatedsimple_qtype
  37. */
  38. public $qtypeobj;
  39. public $wildcarddisplay;
  40. public $questiondisplay;
  41. public $datasetdefs;
  42. public $reload = false;
  43. public $maxnumber = -1;
  44. public $regenerate = true;
  45. public $noofitems;
  46. public $outsidelimit = false;
  47. public $commentanswer = array();
  48. public $answer = array();
  49. public $nonemptyanswer = array();
  50. public $numbererrors = array();
  51. public $formdata = array();
  52. public function __construct($submiturl, $question, $category, $contexts, $formeditable = true) {
  53. $this->regenerate = true;
  54. $this->question = $question;
  55. $this->qtypeobj = question_bank::get_qtype($this->question->qtype);
  56. // Get the dataset definitions for this question.
  57. // Coming here everytime even when using a NoSubmitButton.
  58. // This will only set the values to the actual question database content
  59. // which is not what we want, so this should be removed from here.
  60. // Get priority to paramdatasets.
  61. $this->reload = optional_param('reload', false, PARAM_BOOL);
  62. if (!$this->reload) { // Use database data as this is first pass
  63. // Question->id == 0 so no stored datasets.
  64. if (!empty($question->id)) {
  65. $this->datasetdefs = $this->qtypeobj->get_dataset_definitions(
  66. $question->id, array());
  67. if (!empty($this->datasetdefs)) {
  68. foreach ($this->datasetdefs as $defid => $datasetdef) {
  69. // First get the items in case their number does not correspond to itemcount.
  70. if (isset($datasetdef->id)) {
  71. $this->datasetdefs[$defid]->items =
  72. $this->qtypeobj->get_database_dataset_items($datasetdef->id);
  73. if ($this->datasetdefs[$defid]->items != '') {
  74. $datasetdef->itemcount = count($this->datasetdefs[$defid]->items);
  75. } else {
  76. $datasetdef->itemcount = 0;
  77. }
  78. }
  79. // Get maxnumber.
  80. if ($this->maxnumber == -1 || $datasetdef->itemcount < $this->maxnumber) {
  81. $this->maxnumber = $datasetdef->itemcount;
  82. }
  83. }
  84. }
  85. $i = 0;
  86. foreach ($this->question->options->answers as $answer) {
  87. $this->answer[$i] = $answer;
  88. $i++;
  89. }
  90. $this->nonemptyanswer = $this->answer;
  91. }
  92. $datasettoremove = false;
  93. $newdatasetvalues = false;
  94. $newdataset = false;
  95. } else {
  96. // Handle reload to get values from the form-elements
  97. // answers, datasetdefs and data_items. In any case the validation
  98. // step will warn the user of any error in settings the values.
  99. // Verification for the specific dataset values as the other parameters
  100. // units, feeedback etc are handled elsewhere.
  101. // Handle request buttons :
  102. // 'analyzequestion' (Identify the wild cards {x..} present in answers).
  103. // 'addbutton' (create new set of datatitems).
  104. // 'updatedatasets' is handled automatically on each reload.
  105. // The analyzequestion is done every time on reload
  106. // to detect any new wild cards so that the current display reflects
  107. // the mandatory (i.e. in answers) datasets.
  108. // To implement : don't do any changes if the question is used in a quiz.
  109. // If new datadef, new properties should erase items.
  110. // most of the data.
  111. $datasettoremove = false;
  112. $newdatasetvalues = false;
  113. $newdataset = false;
  114. $dummyform = new stdClass();
  115. $mandatorydatasets = array();
  116. // Should not test on adding a new answer.
  117. // Should test if there are already olddatasets or if the 'analyzequestion'.
  118. // submit button has been clicked.
  119. if (optional_param_array('datasetdef', false, PARAM_BOOL) ||
  120. optional_param('analyzequestion', false, PARAM_BOOL)) {
  121. if ($dummyform->answer = optional_param_array('answer', '', PARAM_NOTAGS)) {
  122. // There is always at least one answer...
  123. $fraction = optional_param_array('fraction', '', PARAM_FLOAT);
  124. $tolerance = optional_param_array('tolerance', '', PARAM_LOCALISEDFLOAT);
  125. $tolerancetype = optional_param_array('tolerancetype', '', PARAM_FLOAT);
  126. $correctanswerlength = optional_param_array('correctanswerlength', '', PARAM_INT);
  127. $correctanswerformat = optional_param_array('correctanswerformat', '', PARAM_INT);
  128. foreach ($dummyform->answer as $key => $answer) {
  129. if (trim($answer) != '') { // Just look for non-empty.
  130. $this->answer[$key] = new stdClass();
  131. $this->answer[$key]->answer = $answer;
  132. $this->answer[$key]->fraction = $fraction[$key];
  133. $this->answer[$key]->tolerance = $tolerance[$key];
  134. $this->answer[$key]->tolerancetype = $tolerancetype[$key];
  135. $this->answer[$key]->correctanswerlength = $correctanswerlength[$key];
  136. $this->answer[$key]->correctanswerformat = $correctanswerformat[$key];
  137. $this->nonemptyanswer[]= $this->answer[$key];
  138. $mandatorydatasets += $this->qtypeobj->find_dataset_names($answer);
  139. }
  140. }
  141. }
  142. $this->datasetdefs = array();
  143. // Rebuild datasetdefs from old values.
  144. if ($olddef = optional_param_array('datasetdef', '', PARAM_RAW)) {
  145. $calcmin = optional_param_array('calcmin', '', PARAM_LOCALISEDFLOAT);
  146. $calclength = optional_param_array('calclength', '', PARAM_INT);
  147. $calcmax = optional_param_array('calcmax', '', PARAM_LOCALISEDFLOAT);
  148. $oldoptions = optional_param_array('defoptions', '', PARAM_RAW);
  149. $newdatasetvalues = false;
  150. $sizeofolddef = count($olddef);
  151. for ($key = 1; $key <= $sizeofolddef; $key++) {
  152. $def = $olddef[$key];
  153. $this->datasetdefs[$def]= new stdClass();
  154. $this->datasetdefs[$def]->type = 1;
  155. $this->datasetdefs[$def]->category = 0;
  156. $this->datasetdefs[$def]->options = $oldoptions[$key];
  157. $this->datasetdefs[$def]->calcmin = $calcmin[$key];
  158. $this->datasetdefs[$def]->calcmax = $calcmax[$key];
  159. $this->datasetdefs[$def]->calclength = $calclength[$key];
  160. // Then compare with new values.
  161. if (preg_match('~^(uniform|loguniform):([^:]*):([^:]*):([0-9]*)$~',
  162. $this->datasetdefs[$def]->options, $regs)) {
  163. if ($this->datasetdefs[$def]->calcmin != $regs[2]||
  164. $this->datasetdefs[$def]->calcmax != $regs[3] ||
  165. $this->datasetdefs[$def]->calclength != $regs[4]) {
  166. $newdatasetvalues = true;
  167. }
  168. }
  169. $this->datasetdefs[$def]->options = "uniform:" .
  170. $this->datasetdefs[$def]->calcmin . ":" .
  171. $this->datasetdefs[$def]->calcmax . ":" .
  172. $this->datasetdefs[$def]->calclength;
  173. }
  174. }
  175. // Detect new datasets.
  176. $newdataset = false;
  177. foreach ($mandatorydatasets as $datasetname) {
  178. if (!isset($this->datasetdefs["1-0-{$datasetname}"])) {
  179. $key = "1-0-{$datasetname}";
  180. $this->datasetdefs[$key] = new stdClass();
  181. $this->datasetdefs[$key]->type = 1;
  182. $this->datasetdefs[$key]->category = 0;
  183. $this->datasetdefs[$key]->name = $datasetname;
  184. $this->datasetdefs[$key]->options = "uniform:1.0:10.0:1";
  185. $newdataset = true;
  186. } else {
  187. $this->datasetdefs["1-0-{$datasetname}"]->name = $datasetname;
  188. }
  189. }
  190. // Remove obsolete datasets.
  191. $datasettoremove = false;
  192. foreach ($this->datasetdefs as $defkey => $datasetdef) {
  193. if (!isset($datasetdef->name)) {
  194. $datasettoremove = true;
  195. unset($this->datasetdefs[$defkey]);
  196. }
  197. }
  198. }
  199. } // Handle reload.
  200. // Create items if $newdataset and noofitems > 0 and !$newdatasetvalues.
  201. // Eliminate any items if $newdatasetvalues.
  202. // Eliminate any items if $datasettoremove, $newdataset, $newdatasetvalues.
  203. if ($datasettoremove ||$newdataset ||$newdatasetvalues) {
  204. foreach ($this->datasetdefs as $defkey => $datasetdef) {
  205. $datasetdef->itemcount = 0;
  206. unset($datasetdef->items);
  207. }
  208. }
  209. $maxnumber = -1;
  210. if (optional_param('addbutton', false, PARAM_BOOL)) {
  211. $maxnumber = optional_param('selectadd', '', PARAM_INT); // FIXME: sloppy coding.
  212. foreach ($this->datasetdefs as $defid => $datasetdef) {
  213. $datasetdef->itemcount = $maxnumber;
  214. unset($datasetdef->items);
  215. for ($numberadded = 1; $numberadded <= $maxnumber; $numberadded++) {
  216. $datasetitem = new stdClass();
  217. $datasetitem->itemnumber = $numberadded;
  218. $datasetitem->id = 0;
  219. $datasetitem->value = $this->qtypeobj->generate_dataset_item(
  220. $datasetdef->options);
  221. $this->datasetdefs[$defid]->items[$numberadded] = $datasetitem;
  222. }
  223. }
  224. $this->maxnumber = $maxnumber;
  225. } else {
  226. // Handle reload dataset items.
  227. if (optional_param_array('definition', '', PARAM_NOTAGS) &&
  228. !($datasettoremove ||$newdataset ||$newdatasetvalues)) {
  229. $i = 1;
  230. $fromformdefinition = optional_param_array('definition', '', PARAM_NOTAGS);
  231. $fromformnumber = optional_param_array('number', '', PARAM_LOCALISEDFLOAT);
  232. $fromformitemid = optional_param_array('itemid', '', PARAM_INT);
  233. ksort($fromformdefinition);
  234. foreach ($fromformdefinition as $key => $defid) {
  235. $addeditem = new stdClass();
  236. $addeditem->id = $fromformitemid[$i];
  237. $addeditem->value = $fromformnumber[$i];
  238. $addeditem->itemnumber = ceil($i / count($this->datasetdefs));
  239. $this->datasetdefs[$defid]->items[$addeditem->itemnumber] = $addeditem;
  240. $this->datasetdefs[$defid]->itemcount = $i;
  241. $i++;
  242. }
  243. }
  244. if (isset($addeditem->itemnumber) && $this->maxnumber < $addeditem->itemnumber) {
  245. $this->maxnumber = $addeditem->itemnumber;
  246. if (!empty($this->datasetdefs)) {
  247. foreach ($this->datasetdefs as $datasetdef) {
  248. $datasetdef->itemcount = $this->maxnumber;
  249. }
  250. }
  251. }
  252. }
  253. parent::__construct($submiturl, $question, $category, $contexts, $formeditable);
  254. }
  255. /**
  256. * Add question-type specific form fields.
  257. *
  258. * @param MoodleQuickForm $mform the form being built.
  259. */
  260. protected function definition_inner($mform) {
  261. $strquestionlabel = $this->qtypeobj->comment_header($this->nonemptyanswer);
  262. $label = get_string("sharedwildcards", "qtype_calculated");
  263. $mform->addElement('hidden', 'synchronize', 0);
  264. $mform->addElement('hidden', 'initialcategory', 1);
  265. $mform->setType('synchronize', PARAM_BOOL);
  266. $mform->setType('initialcategory', PARAM_INT);
  267. $mform->addElement('hidden', 'reload', 1);
  268. $mform->setType('reload', PARAM_INT);
  269. $addfieldsname = 'updatequestion value';
  270. $addstring = get_string("updatecategory", "qtype_calculated");
  271. $mform->registerNoSubmitButton($addfieldsname);
  272. $this->add_per_answer_fields($mform, get_string('answerhdr', 'qtype_calculated', '{no}'),
  273. question_bank::fraction_options(), 1, 1);
  274. $this->add_unit_options($mform, $this);
  275. $this->add_unit_fields($mform, $this);
  276. $this->add_interactive_settings();
  277. $label = "<div class='mdl-align'></div><div class='mdl-align'>" .
  278. get_string('wildcardrole', 'qtype_calculatedsimple') . "</div>";
  279. $mform->addElement('html', "<div class='mdl-align'>&nbsp;</div>");
  280. // Explaining the role of datasets so other strings can be shortened.
  281. $mform->addElement('html', $label);
  282. $mform->addElement('submit', 'analyzequestion',
  283. get_string('findwildcards', 'qtype_calculatedsimple'));
  284. $mform->registerNoSubmitButton('analyzequestion');
  285. $mform->closeHeaderBefore('analyzequestion');
  286. $this->wizarddisplay = optional_param('analyzequestion', false, PARAM_BOOL);
  287. if ($this->maxnumber != -1) {
  288. $this->noofitems = $this->maxnumber;
  289. } else {
  290. $this->noofitems = 0;
  291. }
  292. if (!empty($this->datasetdefs)) {// So there are some datadefs.
  293. // We put them on the page.
  294. $key = 0;
  295. $mform->addElement('header', 'additemhdr',
  296. get_string('wildcardparam', 'qtype_calculatedsimple'));
  297. $idx = 1;
  298. if (!empty($this->datasetdefs)) {// Unnecessary test.
  299. $j = (($this->noofitems) * count($this->datasetdefs))+1;//
  300. foreach ($this->datasetdefs as $defkey => $datasetdef) {
  301. $mform->addElement('static', "na[{$j}]",
  302. get_string('param', 'qtype_calculated', $datasetdef->name));
  303. $this->qtypeobj->custom_generator_tools_part($mform, $idx, $j);
  304. $mform->addElement('hidden', "datasetdef[{$idx}]");
  305. $mform->setType("datasetdef[{$idx}]", PARAM_RAW);
  306. $mform->addElement('hidden', "defoptions[{$idx}]");
  307. $mform->setType("defoptions[{$idx}]", PARAM_RAW);
  308. $idx++;
  309. $mform->addElement('static', "divider[{$j}]", '', '<hr />');
  310. $j++;
  311. }
  312. }
  313. // This should be done before the elements are created and stored as $this->formdata.
  314. // Fill out all data sets and also the fields for the next item to add.
  315. /*Here we do already the values error analysis so that
  316. * we could force all wild cards values display if there is an error in values.
  317. * as using a , in a number */
  318. $this->numbererrors = array();
  319. if (!empty($this->datasetdefs)) {
  320. $j = $this->noofitems * count($this->datasetdefs);
  321. for ($itemnumber = $this->noofitems; $itemnumber >= 1; $itemnumber--) {
  322. $data = array();
  323. $numbererrors = '';
  324. $comment = new stdClass();
  325. $comment->stranswers = array();
  326. $comment->outsidelimit = false;
  327. $comment->answers = array();
  328. foreach ($this->datasetdefs as $defid => $datasetdef) {
  329. if (isset($datasetdef->items[$itemnumber])) {
  330. $this->formdata["definition[{$j}]"] = $defid;
  331. $this->formdata["itemid[{$j}]"] =
  332. $datasetdef->items[$itemnumber]->id;
  333. $data[$datasetdef->name] = $datasetdef->items[$itemnumber]->value;
  334. $this->formdata["number[{$j}]"] = $number =
  335. $datasetdef->items[$itemnumber]->value;
  336. if (! is_numeric($number)) {
  337. $a = new stdClass();
  338. $a->name = '{'.$datasetdef->name.'}';
  339. $a->value = $datasetdef->items[$itemnumber]->value;
  340. if (stristr($number, ',')) {
  341. $this->numbererrors["number[{$j}]"] =
  342. get_string('nocommaallowed', 'qtype_calculated');
  343. $numbererrors .= $this->numbererrors['number['.$j.']']."<br />";
  344. } else {
  345. $this->numbererrors["number[{$j}]"] =
  346. get_string('notvalidnumber', 'qtype_calculated', $a);
  347. $numbererrors .= $this->numbererrors['number['.$j.']']."<br />";
  348. }
  349. } else if (stristr($number, 'x')) { // Hexa will pass the test.
  350. $a = new stdClass();
  351. $a->name = '{'.$datasetdef->name.'}';
  352. $a->value = $datasetdef->items[$itemnumber]->value;
  353. $this->numbererrors['number['.$j.']'] =
  354. get_string('hexanotallowed', 'qtype_calculated', $a);
  355. $numbererrors .= $this->numbererrors['number['.$j.']']."<br />";
  356. } else if (is_nan($number)) {
  357. $a = new stdClass();
  358. $a->name = '{'.$datasetdef->name.'}';
  359. $a->value = $datasetdef->items[$itemnumber]->value;
  360. $this->numbererrors["number[{$j}]"] =
  361. get_string('notvalidnumber', 'qtype_calculated', $a);
  362. $numbererrors .= $this->numbererrors['number['.$j.']']."<br />";
  363. }
  364. }
  365. $j--;
  366. }
  367. if ($this->noofitems != 0) {
  368. if (empty($numbererrors)) {
  369. if (!isset($this->question->id)) {
  370. $this->question->id = 0;
  371. }
  372. $this->question->questiontext = !empty($this->question->questiontext) ?
  373. $this->question->questiontext : '';
  374. $comment = $this->qtypeobj->comment_on_datasetitems(
  375. $this->qtypeobj, $this->question->id,
  376. $this->question->questiontext, $this->nonemptyanswer,
  377. $data, $itemnumber);
  378. if ($comment->outsidelimit) {
  379. $this->outsidelimit = $comment->outsidelimit;
  380. }
  381. $totalcomment = '';
  382. foreach ($this->nonemptyanswer as $key => $answer) {
  383. $totalcomment .= $comment->stranswers[$key].'<br/>';
  384. }
  385. $this->formdata['answercomment['.$itemnumber.']'] = $totalcomment;
  386. }
  387. }
  388. }
  389. $this->formdata['selectdelete'] = '1';
  390. $this->formdata['selectadd'] = '1';
  391. $j = $this->noofitems * count($this->datasetdefs)+1;
  392. $data = array(); // Data for comment_on_datasetitems later.
  393. $idx = 1;
  394. foreach ($this->datasetdefs as $defid => $datasetdef) {
  395. $this->formdata["datasetdef[{$idx}]"] = $defid;
  396. $idx++;
  397. }
  398. $this->formdata = $this->qtypeobj->custom_generator_set_data(
  399. $this->datasetdefs, $this->formdata);
  400. }
  401. $addoptions = Array();
  402. $addoptions['1'] = '1';
  403. for ($i = 10; $i <= 100; $i += 10) {
  404. $addoptions["{$i}"] = "{$i}";
  405. }
  406. $showoptions = Array();
  407. $showoptions['1'] = '1';
  408. $showoptions['2'] = '2';
  409. $showoptions['5'] = '5';
  410. for ($i = 10; $i <= 100; $i += 10) {
  411. $showoptions["{$i}"] = "{$i}";
  412. }
  413. $mform->closeHeaderBefore('additemhdr');
  414. $addgrp = array();
  415. $addgrp[] = $mform->createElement('submit', 'addbutton',
  416. get_string('generatenewitemsset', 'qtype_calculatedsimple'));
  417. $addgrp[] = $mform->createElement('select', "selectadd", '', $addoptions);
  418. $addgrp[] = $mform->createElement('static', "stat", '',
  419. get_string('newsetwildcardvalues', 'qtype_calculatedsimple'));
  420. $mform->addGroup($addgrp, 'addgrp', '', ' ', false);
  421. $mform->registerNoSubmitButton('addbutton');
  422. $mform->closeHeaderBefore('addgrp');
  423. $addgrp1 = array();
  424. $addgrp1[] = $mform->createElement('submit', 'showbutton',
  425. get_string('showitems', 'qtype_calculatedsimple'));
  426. $addgrp1[] = $mform->createElement('select', "selectshow", '', $showoptions);
  427. $addgrp1[] = $mform->createElement('static', "stat", '',
  428. get_string('setwildcardvalues', 'qtype_calculatedsimple'));
  429. $mform->addGroup($addgrp1, 'addgrp1', '', ' ', false);
  430. $mform->registerNoSubmitButton('showbutton');
  431. $mform->closeHeaderBefore('addgrp1');
  432. $mform->addElement('static', "divideradd", '', '');
  433. if ($this->noofitems == 0) {
  434. $mform->addElement('static', 'warningnoitems', '', '<span class="error">' .
  435. get_string('youmustaddatleastonevalue', 'qtype_calculatedsimple') .
  436. '</span>');
  437. $mform->closeHeaderBefore('warningnoitems');
  438. } else {
  439. $mform->addElement('header', 'additemhdr1',
  440. get_string('wildcardvalues', 'qtype_calculatedsimple'));
  441. $mform->closeHeaderBefore('additemhdr1');
  442. if (!empty($this->numbererrors) || $this->outsidelimit) {
  443. $mform->addElement('static', "alert", '', '<span class="error">' .
  444. get_string('useadvance', 'qtype_calculatedsimple').'</span>');
  445. }
  446. $mform->addElement('submit', 'updatedatasets',
  447. get_string('updatewildcardvalues', 'qtype_calculatedsimple'));
  448. $mform->registerNoSubmitButton('updatedatasets');
  449. $mform->setAdvanced("updatedatasets", true);
  450. // ...--------------------------------------------------------------.
  451. $j = $this->noofitems * count($this->datasetdefs);
  452. $k = optional_param('selectshow', 1, PARAM_INT);
  453. for ($i = $this->noofitems; $i >= 1; $i--) {
  454. foreach ($this->datasetdefs as $defkey => $datasetdef) {
  455. if ($k > 0 || $this->outsidelimit || !empty($this->numbererrors)) {
  456. $mform->addElement('float', "number[{$j}]", get_string(
  457. 'wildcard', 'qtype_calculatedsimple', $datasetdef->name));
  458. $mform->setAdvanced("number[{$j}]", true);
  459. if (!empty($this->numbererrors['number['.$j.']'])) {
  460. $mform->addElement('static', "numbercomment[{$j}]", '',
  461. '<span class="error">' .
  462. $this->numbererrors['number['.$j.']'] . '</span>');
  463. $mform->setAdvanced("numbercomment[{$j}]", true);
  464. }
  465. } else {
  466. $mform->addElement('hidden', "number[{$j}]", '');
  467. $mform->setType("number[{$j}]", PARAM_LOCALISEDFLOAT); // Localisation handling has to be done manually.
  468. if (isset($this->formdata["number[{$j}]"])) {
  469. $this->formdata["number[{$j}]"] = format_float($this->formdata["number[{$j}]"], -1);
  470. }
  471. }
  472. $mform->addElement('hidden', "itemid[{$j}]");
  473. $mform->setType("itemid[{$j}]", PARAM_INT);
  474. $mform->addElement('hidden', "definition[{$j}]");
  475. $mform->setType("definition[{$j}]", PARAM_NOTAGS);
  476. $j--;
  477. }
  478. if (!empty($strquestionlabel) && ($k > 0 || $this->outsidelimit ||
  479. !empty($this->numbererrors))) {
  480. $mform->addElement('static', "answercomment[{$i}]", "<b>" .
  481. get_string('setno', 'qtype_calculatedsimple', $i) .
  482. "</b>&nbsp;&nbsp;" . $strquestionlabel);
  483. }
  484. if ($k > 0 || $this->outsidelimit || !empty($this->numbererrors)) {
  485. $mform->addElement('static', "divider1[{$j}]", '', '<hr />');
  486. }
  487. $k--;
  488. }
  489. }
  490. } else {
  491. $mform->addElement('static', 'warningnowildcards', '', '<span class="error">' .
  492. get_string('atleastonewildcard', 'qtype_calculatedsimple') . '</span>');
  493. $mform->closeHeaderBefore('warningnowildcards');
  494. }
  495. // ...----------------------------------------------------------------------.
  496. // Non standard name for button element needed so not using add_action_buttons.
  497. // Hidden elements.
  498. $mform->addElement('hidden', 'id');
  499. $mform->setType('id', PARAM_INT);
  500. $mform->addElement('hidden', 'courseid');
  501. $mform->setType('courseid', PARAM_INT);
  502. $mform->setDefault('courseid', 0);
  503. $mform->addElement('hidden', 'cmid');
  504. $mform->setType('cmid', PARAM_INT);
  505. $mform->setDefault('cmid', 0);
  506. if (!empty($this->question->id)) {
  507. if ($this->question->formoptions->cansaveasnew) {
  508. $mform->addElement('header', 'additemhdr',
  509. get_string('converttocalculated', 'qtype_calculatedsimple'));
  510. $mform->closeHeaderBefore('additemhdr');
  511. $mform->addElement('checkbox', 'convert', '',
  512. get_string('willconverttocalculated', 'qtype_calculatedsimple'));
  513. $mform->setDefault('convert', 0);
  514. }
  515. }
  516. }
  517. protected function can_preview() {
  518. return empty($this->question->beingcopied) && !empty($this->question->id) &&
  519. $this->question->formoptions->canedit && $this->noofitems > 0;
  520. }
  521. public function data_preprocessing($question) {
  522. $question = parent::data_preprocessing($question);
  523. $question = $this->data_preprocessing_answers($question);
  524. $question = $this->data_preprocessing_hints($question);
  525. $question = $this->data_preprocessing_units($question);
  526. $question = $this->data_preprocessing_unit_options($question);
  527. // This is a bit ugly, but it loads all the dataset values.
  528. $question = (object)((array)$question + $this->formdata);
  529. return $question;
  530. }
  531. public function qtype() {
  532. return 'calculatedsimple';
  533. }
  534. public function validation($data, $files) {
  535. $errors = parent::validation($data, $files);
  536. if (array_key_exists('number', $data)) {
  537. $numbers = $data['number'];
  538. } else {
  539. $numbers = array();
  540. }
  541. foreach ($numbers as $key => $number) {
  542. if (! is_numeric($number)) {
  543. if (stristr($number, ',')) {
  544. $errors['number['.$key.']'] = get_string('nocommaallowed', 'qtype_calculated');
  545. } else {
  546. $errors['number['.$key.']'] = get_string('notvalidnumber', 'qtype_calculated');
  547. }
  548. } else if (stristr($number, 'x')) {
  549. $a = new stdClass();
  550. $a->name = '';
  551. $a->value = $number;
  552. $errors['number['.$key.']'] = get_string('hexanotallowed', 'qtype_calculated', $a);
  553. } else if (is_nan($number)) {
  554. $errors['number['.$key.']'] = get_string('notvalidnumber', 'qtype_calculated');
  555. }
  556. }
  557. if (empty($data['definition'])) {
  558. $errors['selectadd'] = get_string('youmustaddatleastonevalue', 'qtype_calculatedsimple');
  559. }
  560. return $errors;
  561. }
  562. }